2026-03-30 21:42:52 +01:00
|
|
|
package internal
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/csv"
|
|
|
|
|
"errors"
|
|
|
|
|
"io"
|
|
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Headings []string
|
|
|
|
|
|
|
|
|
|
func (h Headings) IndexOf(heading string) int {
|
|
|
|
|
for i, value := range h {
|
|
|
|
|
if value == heading {
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ReadCsvRedirects(file string) (Redirects, error) {
|
|
|
|
|
reader, err := os.Open(file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
csvReader := csv.NewReader(reader)
|
|
|
|
|
|
|
|
|
|
// Process headings
|
|
|
|
|
textHeadings, err := csvReader.Read()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
headings := Headings(textHeadings)
|
|
|
|
|
fromCol := headings.IndexOf("From")
|
|
|
|
|
toCol := headings.IndexOf("To")
|
|
|
|
|
statusCol := headings.IndexOf("Status Code")
|
|
|
|
|
if fromCol == -1 || toCol == -1 || statusCol == -1 {
|
|
|
|
|
return nil, errors.New("CSV must contain From, To, and Status Code headings")
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 21:51:48 +01:00
|
|
|
// Read data
|
2026-03-30 21:42:52 +01:00
|
|
|
redirects := Redirects{}
|
2026-03-30 21:51:48 +01:00
|
|
|
|
2026-03-30 21:42:52 +01:00
|
|
|
for {
|
|
|
|
|
row, err := csvReader.Read()
|
|
|
|
|
if err != nil {
|
|
|
|
|
if errors.Is(err, io.EOF) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if row == nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
statusCode, err := strconv.Atoi(row[statusCol])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
redirect := &Redirect{
|
|
|
|
|
From: row[fromCol],
|
|
|
|
|
To: row[toCol],
|
|
|
|
|
StatusCode: statusCode,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
redirects = append(redirects, redirect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirects, nil
|
|
|
|
|
}
|