package controllers import ( "fmt" "fotbal-club/pkg/logger" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // BatchOperationsController handles bulk operations type BatchOperationsController struct { DB *gorm.DB } // NewBatchOperationsController creates a new BatchOperationsController instance func NewBatchOperationsController(db *gorm.DB) *BatchOperationsController { return &BatchOperationsController{DB: db} } // BatchDeleteRequest represents a batch delete request type BatchDeleteRequest struct { IDs []uint `json:"ids" binding:"required,min=1"` } // BatchUpdateRequest represents a batch update request type BatchUpdateRequest struct { IDs []uint `json:"ids" binding:"required,min=1"` Fields map[string]interface{} `json:"fields" binding:"required"` } // BatchResult represents the result of a batch operation type BatchResult struct { Success bool `json:"success"` TotalItems int `json:"total_items"` SuccessCount int `json:"success_count"` FailureCount int `json:"failure_count"` Errors []string `json:"errors,omitempty"` } // BatchDelete performs a batch delete operation func (boc *BatchOperationsController) BatchDelete(c *gin.Context, model interface{}, tableName string) { var req BatchDeleteRequest if err := c.ShouldBindJSON(&req); err != nil { Respond.BadRequest(c, "Invalid request: "+err.Error()) return } if len(req.IDs) == 0 { Respond.BadRequest(c, "No IDs provided") return } // Perform batch delete result := boc.DB.Where("id IN ?", req.IDs).Delete(model) if result.Error != nil { logger.Error("Batch delete failed for %s: %v", tableName, result.Error) Respond.InternalError(c, "Failed to perform batch delete") return } batchResult := BatchResult{ Success: true, TotalItems: len(req.IDs), SuccessCount: int(result.RowsAffected), FailureCount: len(req.IDs) - int(result.RowsAffected), } logger.Info("Batch deleted %d %s records", result.RowsAffected, tableName) Respond.Success(c, batchResult, fmt.Sprintf("Successfully deleted %d items", result.RowsAffected)) } // BatchUpdate performs a batch update operation func (boc *BatchOperationsController) BatchUpdate(c *gin.Context, model interface{}, tableName string, allowedFields []string) { var req BatchUpdateRequest if err := c.ShouldBindJSON(&req); err != nil { Respond.BadRequest(c, "Invalid request: "+err.Error()) return } if len(req.IDs) == 0 { Respond.BadRequest(c, "No IDs provided") return } if len(req.Fields) == 0 { Respond.BadRequest(c, "No fields to update") return } // Validate fields updates := make(map[string]interface{}) for field, value := range req.Fields { allowed := false for _, af := range allowedFields { if field == af { allowed = true break } } if !allowed { Respond.BadRequest(c, fmt.Sprintf("Field '%s' is not allowed for batch update", field)) return } updates[field] = value } // Perform batch update result := boc.DB.Model(model).Where("id IN ?", req.IDs).Updates(updates) if result.Error != nil { logger.Error("Batch update failed for %s: %v", tableName, result.Error) Respond.InternalError(c, "Failed to perform batch update") return } batchResult := BatchResult{ Success: true, TotalItems: len(req.IDs), SuccessCount: int(result.RowsAffected), FailureCount: len(req.IDs) - int(result.RowsAffected), } logger.Info("Batch updated %d %s records", result.RowsAffected, tableName) Respond.Success(c, batchResult, fmt.Sprintf("Successfully updated %d items", result.RowsAffected)) } // BatchPublish publishes/unpublishes multiple items (for publishable entities) func (boc *BatchOperationsController) BatchPublish(c *gin.Context, model interface{}, tableName string, publish bool) { var req BatchDeleteRequest if err := c.ShouldBindJSON(&req); err != nil { Respond.BadRequest(c, "Invalid request: "+err.Error()) return } if len(req.IDs) == 0 { Respond.BadRequest(c, "No IDs provided") return } // Update published status result := boc.DB.Model(model).Where("id IN ?", req.IDs).Update("published", publish) if result.Error != nil { logger.Error("Batch publish failed for %s: %v", tableName, result.Error) Respond.InternalError(c, "Failed to perform batch publish") return } action := "published" if !publish { action = "unpublished" } batchResult := BatchResult{ Success: true, TotalItems: len(req.IDs), SuccessCount: int(result.RowsAffected), FailureCount: len(req.IDs) - int(result.RowsAffected), } logger.Info("Batch %s %d %s records", action, result.RowsAffected, tableName) Respond.Success(c, batchResult, fmt.Sprintf("Successfully %s %d items", action, result.RowsAffected)) } // BatchArchive archives/unarchives multiple items (for archivable entities) func (boc *BatchOperationsController) BatchArchive(c *gin.Context, model interface{}, tableName string, archive bool) { var req BatchDeleteRequest if err := c.ShouldBindJSON(&req); err != nil { Respond.BadRequest(c, "Invalid request: "+err.Error()) return } if len(req.IDs) == 0 { Respond.BadRequest(c, "No IDs provided") return } // Update archived status result := boc.DB.Model(model).Where("id IN ?", req.IDs).Update("archived", archive) if result.Error != nil { logger.Error("Batch archive failed for %s: %v", tableName, result.Error) Respond.InternalError(c, "Failed to perform batch archive") return } action := "archived" if !archive { action = "unarchived" } batchResult := BatchResult{ Success: true, TotalItems: len(req.IDs), SuccessCount: int(result.RowsAffected), FailureCount: len(req.IDs) - int(result.RowsAffected), } logger.Info("Batch %s %d %s records", action, result.RowsAffected, tableName) Respond.Success(c, batchResult, fmt.Sprintf("Successfully %s %d items", action, result.RowsAffected)) } // BatchReorder reorders items based on provided order func (boc *BatchOperationsController) BatchReorder(c *gin.Context, model interface{}, tableName string) { var req struct { Orders []struct { ID uint `json:"id" binding:"required"` Order int `json:"order" binding:"required"` } `json:"orders" binding:"required,min=1"` } if err := c.ShouldBindJSON(&req); err != nil { Respond.BadRequest(c, "Invalid request: "+err.Error()) return } // Update order for each item successCount := 0 errors := []string{} for _, item := range req.Orders { result := boc.DB.Model(model).Where("id = ?", item.ID).Update("display_order", item.Order) if result.Error != nil { errors = append(errors, fmt.Sprintf("Failed to update order for ID %d: %v", item.ID, result.Error)) continue } successCount++ } batchResult := BatchResult{ Success: len(errors) == 0, TotalItems: len(req.Orders), SuccessCount: successCount, FailureCount: len(errors), Errors: errors, } if len(errors) > 0 { logger.Warn("Batch reorder partially failed for %s: %d successes, %d failures", tableName, successCount, len(errors)) Respond.Custom(c, 207, false, batchResult, "", "Batch reorder completed with errors") // 207 Multi-Status return } logger.Info("Batch reordered %d %s records", successCount, tableName) Respond.Success(c, batchResult, fmt.Sprintf("Successfully reordered %d items", successCount)) } // BatchDuplicate duplicates multiple items func (boc *BatchOperationsController) BatchDuplicate(c *gin.Context, tableName string, duplicateFunc func(id uint) error) { var req BatchDeleteRequest if err := c.ShouldBindJSON(&req); err != nil { Respond.BadRequest(c, "Invalid request: "+err.Error()) return } if len(req.IDs) == 0 { Respond.BadRequest(c, "No IDs provided") return } // Duplicate each item successCount := 0 errors := []string{} for _, id := range req.IDs { if err := duplicateFunc(id); err != nil { errors = append(errors, fmt.Sprintf("Failed to duplicate ID %d: %v", id, err)) continue } successCount++ } batchResult := BatchResult{ Success: len(errors) == 0, TotalItems: len(req.IDs), SuccessCount: successCount, FailureCount: len(errors), Errors: errors, } if len(errors) > 0 { logger.Warn("Batch duplicate partially failed for %s: %d successes, %d failures", tableName, successCount, len(errors)) Respond.Custom(c, 207, false, batchResult, "", "Batch duplicate completed with errors") return } logger.Info("Batch duplicated %d %s records", successCount, tableName) Respond.Success(c, batchResult, fmt.Sprintf("Successfully duplicated %d items", successCount)) } // Global BatchOperationsController instance (needs to be initialized with DB) var BatchOps *BatchOperationsController // InitBatchOperations initializes the global batch operations controller func InitBatchOperations(db *gorm.DB) { BatchOps = NewBatchOperationsController(db) }