mirror of
https://github.com/therootcompany/golib.git
synced 2026-01-27 23:18:05 +00:00
106 lines
2.4 KiB
Go
106 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"fmt"
|
|
"io"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/therootcompany/golib/net/smsgw"
|
|
)
|
|
|
|
func GetFieldIndex(header []string, name string) int {
|
|
for i, h := range header {
|
|
if strings.EqualFold(strings.TrimSpace(h), name) {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
type CSVWarn struct {
|
|
Index int
|
|
Code string
|
|
Message string
|
|
Record []string
|
|
}
|
|
|
|
func (w CSVWarn) Error() string {
|
|
return w.Message
|
|
}
|
|
|
|
func (cfg *MainConfig) LaxParseCSV(csvr *csv.Reader) (messages []smsgw.Message, warns []CSVWarn, err error) {
|
|
header, err := csvr.Read()
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("header could not be parsed: %w", err)
|
|
}
|
|
|
|
FIELD_NAME := GetFieldIndex(header, "Name")
|
|
FIELD_PHONE := GetFieldIndex(header, "Phone")
|
|
FIELD_MESSAGE := GetFieldIndex(header, "Message")
|
|
if FIELD_NAME == -1 || FIELD_PHONE == -1 || FIELD_MESSAGE == -1 {
|
|
return nil, nil, fmt.Errorf("header is missing one or more of 'Name', 'Phone', and/or 'Message'")
|
|
}
|
|
FIELD_MIN := 1 + slices.Max([]int{FIELD_NAME, FIELD_PHONE, FIELD_MESSAGE})
|
|
|
|
rowIndex := 1 // 1-index, start at header
|
|
for {
|
|
rowIndex++
|
|
rec, err := csvr.Read()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to parse row %d (and all following rows): %w", rowIndex, err)
|
|
}
|
|
|
|
if len(rec) < FIELD_MIN {
|
|
warns = append(warns, CSVWarn{
|
|
Index: rowIndex,
|
|
Code: "TooFewFields",
|
|
Message: fmt.Sprintf("ignoring row %d: too few fields (want %d, have %d)", rowIndex, FIELD_MIN, len(rec)),
|
|
Record: rec,
|
|
})
|
|
continue
|
|
}
|
|
|
|
vars := make(map[string]string)
|
|
n := min(len(header), len(rec))
|
|
for i := range n {
|
|
switch i {
|
|
case FIELD_NAME, FIELD_PHONE, FIELD_MESSAGE:
|
|
continue
|
|
default:
|
|
key := header[i]
|
|
val := rec[i]
|
|
vars[key] = val
|
|
}
|
|
}
|
|
|
|
message := smsgw.Message{
|
|
// Index: rowIndex,
|
|
Name: strings.TrimSpace(rec[FIELD_NAME]),
|
|
Number: strings.TrimSpace(rec[FIELD_PHONE]),
|
|
Template: strings.TrimSpace(rec[FIELD_MESSAGE]),
|
|
Vars: vars,
|
|
}
|
|
|
|
message.Number = smsgw.StripFormatting(message.Number)
|
|
message.Number, err = smsgw.PrefixUS10Digit(message.Number)
|
|
if err != nil {
|
|
warns = append(warns, CSVWarn{
|
|
Index: rowIndex,
|
|
Code: "PhoneInvalid",
|
|
Message: fmt.Sprintf("ignoring row %d (%s): %s", rowIndex, message.Name, err.Error()),
|
|
Record: rec,
|
|
})
|
|
continue
|
|
}
|
|
|
|
messages = append(messages, message)
|
|
}
|
|
|
|
return messages, warns, nil
|
|
}
|