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:
96
internal/handlers/upload_handler.go
Normal file
96
internal/handlers/upload_handler.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/treytartt/mycrib-api/internal/services"
|
||||
)
|
||||
|
||||
// UploadHandler handles file upload endpoints
|
||||
type UploadHandler struct {
|
||||
storageService *services.StorageService
|
||||
}
|
||||
|
||||
// NewUploadHandler creates a new upload handler
|
||||
func NewUploadHandler(storageService *services.StorageService) *UploadHandler {
|
||||
return &UploadHandler{storageService: storageService}
|
||||
}
|
||||
|
||||
// UploadImage handles POST /api/uploads/image
|
||||
// Accepts multipart/form-data with "file" field
|
||||
func (h *UploadHandler) UploadImage(c *gin.Context) {
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "No file provided"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get category from query param (default: images)
|
||||
category := c.DefaultQuery("category", "images")
|
||||
|
||||
result, err := h.storageService.Upload(file, category)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// UploadDocument handles POST /api/uploads/document
|
||||
// Accepts multipart/form-data with "file" field
|
||||
func (h *UploadHandler) UploadDocument(c *gin.Context) {
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "No file provided"})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.storageService.Upload(file, "documents")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// UploadCompletion handles POST /api/uploads/completion
|
||||
// For task completion photos
|
||||
func (h *UploadHandler) UploadCompletion(c *gin.Context) {
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "No file provided"})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.storageService.Upload(file, "completions")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// DeleteFile handles DELETE /api/uploads
|
||||
// Expects JSON body with "url" field
|
||||
func (h *UploadHandler) DeleteFile(c *gin.Context) {
|
||||
var req struct {
|
||||
URL string `json:"url" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.storageService.Delete(req.URL); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "File deleted successfully"})
|
||||
}
|
||||
Reference in New Issue
Block a user