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:
Trey t
2025-11-27 23:36:20 -06:00
parent 2817deee3c
commit 469f21a833
50 changed files with 6795 additions and 582 deletions

View File

@@ -16,12 +16,16 @@ import (
// ResidenceHandler handles residence-related HTTP requests
type ResidenceHandler struct {
residenceService *services.ResidenceService
pdfService *services.PDFService
emailService *services.EmailService
}
// NewResidenceHandler creates a new residence handler
func NewResidenceHandler(residenceService *services.ResidenceService) *ResidenceHandler {
func NewResidenceHandler(residenceService *services.ResidenceService, pdfService *services.PDFService, emailService *services.EmailService) *ResidenceHandler {
return &ResidenceHandler{
residenceService: residenceService,
pdfService: pdfService,
emailService: emailService,
}
}
@@ -288,7 +292,7 @@ func (h *ResidenceHandler) GetResidenceTypes(c *gin.Context) {
}
// GenerateTasksReport handles POST /api/residences/:id/generate-tasks-report/
// Generates a PDF report of tasks for the residence and optionally emails it
// Generates a PDF report of tasks for the residence and emails it
func (h *ResidenceHandler) GenerateTasksReport(c *gin.Context) {
user := c.MustGet(middleware.AuthUserKey).(*models.User)
@@ -304,7 +308,7 @@ func (h *ResidenceHandler) GenerateTasksReport(c *gin.Context) {
}
c.ShouldBindJSON(&req)
// Generate the report
// Generate the report data
report, err := h.residenceService.GenerateTasksReport(uint(residenceID), user.ID)
if err != nil {
switch {
@@ -318,8 +322,57 @@ func (h *ResidenceHandler) GenerateTasksReport(c *gin.Context) {
return
}
// Determine recipient email
recipientEmail := req.Email
if recipientEmail == "" {
recipientEmail = user.Email
}
// Get recipient name
recipientName := user.FirstName
if recipientName == "" {
recipientName = user.Username
}
// Generate PDF if PDF service is available
var pdfGenerated bool
var emailSent bool
if h.pdfService != nil && h.emailService != nil {
pdfData, pdfErr := h.pdfService.GenerateTasksReportPDF(report)
if pdfErr == nil {
pdfGenerated = true
// Send email with PDF attachment
emailErr := h.emailService.SendTasksReportEmail(
recipientEmail,
recipientName,
report.ResidenceName,
report.TotalTasks,
report.Completed,
report.Pending,
report.Overdue,
pdfData,
)
if emailErr == nil {
emailSent = true
}
}
}
// Build response message
message := "Tasks report generated successfully"
if pdfGenerated && emailSent {
message = "Tasks report generated and sent to " + recipientEmail
} else if pdfGenerated && !emailSent {
message = "Tasks report generated but email could not be sent"
}
c.JSON(http.StatusOK, gin.H{
"message": "Tasks report generated successfully",
"report": report,
"message": message,
"residence_name": report.ResidenceName,
"recipient_email": recipientEmail,
"pdf_generated": pdfGenerated,
"email_sent": emailSent,
"report": report,
})
}