mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
dev day #65
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user