89 lines
1.9 KiB
Go
89 lines
1.9 KiB
Go
package useCases
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/audit"
|
|
"encoding/csv"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const exportBatchSize = 500
|
|
|
|
const formulaGuard = "'"
|
|
const formulaStarts = "=+-@"
|
|
|
|
var exportHeader = []string{"when", "actor", "action", "target", "outcome", "source", "ip"}
|
|
|
|
type ExportActivityUseCase struct {
|
|
events audit.Repository
|
|
now func() time.Time
|
|
}
|
|
|
|
type ActivityExport struct {
|
|
events audit.Repository
|
|
filter audit.Filter
|
|
}
|
|
|
|
func NewExportActivityUseCase(events audit.Repository, now func() time.Time) *ExportActivityUseCase {
|
|
return &ExportActivityUseCase{events, now}
|
|
}
|
|
|
|
func (e *ExportActivityUseCase) Prepare(query ActivityQuery) (*ActivityExport, error) {
|
|
filter, err := buildActivityFilter(query, e.now())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ActivityExport{events: e.events, filter: filter}, nil
|
|
}
|
|
|
|
func (a *ActivityExport) WriteCSV(w io.Writer) error {
|
|
writer := csv.NewWriter(w)
|
|
if err := writer.Write(exportHeader); err != nil {
|
|
return err
|
|
}
|
|
for page := 1; ; page++ {
|
|
filter := a.filter
|
|
filter.Page, filter.Size = page, exportBatchSize
|
|
found, err := a.events.List(filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, event := range found.Items {
|
|
if err := writer.Write(exportRow(event)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
writer.Flush()
|
|
if err := writer.Error(); err != nil {
|
|
return err
|
|
}
|
|
if len(found.Items) < exportBatchSize || page*exportBatchSize >= found.Total {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func exportRow(event audit.Event) []string {
|
|
ip := ""
|
|
if event.IP != nil {
|
|
ip = *event.IP
|
|
}
|
|
return []string{
|
|
event.CreatedAt.UTC().Format(time.RFC3339),
|
|
guardCell(event.Actor.Name),
|
|
guardCell(event.Action),
|
|
guardCell(event.Target.Name),
|
|
string(event.Outcome),
|
|
string(event.Source),
|
|
guardCell(ip),
|
|
}
|
|
}
|
|
|
|
func guardCell(value string) string {
|
|
if value != "" && strings.ContainsRune(formulaStarts, rune(value[0])) {
|
|
return formulaGuard + value
|
|
}
|
|
return value
|
|
}
|