mirror of
https://github.com/therootcompany/golib.git
synced 2026-01-27 23:18:05 +00:00
f: trying to find where the pieces go
This commit is contained in:
parent
fd918575bf
commit
592bbffd6d
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/therootcompany/golib/net/smsgw"
|
"github.com/therootcompany/golib/net/smsgw"
|
||||||
"github.com/therootcompany/golib/net/smsgw/androidsmsgateway"
|
"github.com/therootcompany/golib/net/smsgw/androidsmsgateway"
|
||||||
|
"github.com/therootcompany/golib/net/smsgw/smscsv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MainConfig struct {
|
type MainConfig struct {
|
||||||
@ -122,7 +123,7 @@ func main() {
|
|||||||
csvr := csv.NewReader(file)
|
csvr := csv.NewReader(file)
|
||||||
csvr.FieldsPerRecord = -1
|
csvr.FieldsPerRecord = -1
|
||||||
|
|
||||||
messages, warns, err := cfg.LaxParseCSV(csvr)
|
messages, warns, err := smscsv.ReadOrIgnoreAll(csvr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "\n%sError%s: %v\n", textErr, textReset, err)
|
fmt.Fprintf(os.Stderr, "\n%sError%s: %v\n", textErr, textReset, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@ -1,22 +1,15 @@
|
|||||||
package main
|
package smscsv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/csv"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/therootcompany/golib/net/smsgw"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetFieldIndex(header []string, name string) int {
|
type Reader interface {
|
||||||
for i, h := range header {
|
Read() ([]string, error)
|
||||||
if strings.EqualFold(strings.TrimSpace(h), name) {
|
// ReadAll() ([][]string, error)
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CSVWarn struct {
|
type CSVWarn struct {
|
||||||
@ -30,7 +23,36 @@ func (w CSVWarn) Error() string {
|
|||||||
return w.Message
|
return w.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *MainConfig) LaxParseCSV(csvr *csv.Reader) (messages []smsgw.Message, warns []CSVWarn, err error) {
|
type Message struct {
|
||||||
|
header []string
|
||||||
|
indices map[string]int
|
||||||
|
fields []string
|
||||||
|
Name string
|
||||||
|
Number string
|
||||||
|
Template string
|
||||||
|
Vars map[string]string
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) Size() int {
|
||||||
|
return len(m.fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) Get(key string) string {
|
||||||
|
index, ok := m.indices[key]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m.fields) >= 1+index {
|
||||||
|
return m.fields[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO XXX AJ pass in column name mapping
|
||||||
|
func ReadOrIgnoreAll(csvr Reader) (messages []Message, warns []CSVWarn, err error) {
|
||||||
header, err := csvr.Read()
|
header, err := csvr.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("header could not be parsed: %w", err)
|
return nil, nil, fmt.Errorf("header could not be parsed: %w", err)
|
||||||
@ -55,16 +77,8 @@ func (cfg *MainConfig) LaxParseCSV(csvr *csv.Reader) (messages []smsgw.Message,
|
|||||||
return nil, nil, fmt.Errorf("failed to parse row %d (and all following rows): %w", rowIndex, err)
|
return nil, nil, fmt.Errorf("failed to parse row %d (and all following rows): %w", rowIndex, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rec) < FIELD_MIN {
|
// TODO XXX AJ create an abstraction around the header []string and the record []string
|
||||||
warns = append(warns, CSVWarn{
|
// the idea is to return the same thing for valid and invalid rows
|
||||||
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)
|
vars := make(map[string]string)
|
||||||
n := min(len(header), len(rec))
|
n := min(len(header), len(rec))
|
||||||
for i := range n {
|
for i := range n {
|
||||||
@ -78,7 +92,17 @@ func (cfg *MainConfig) LaxParseCSV(csvr *csv.Reader) (messages []smsgw.Message,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message := smsgw.Message{
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
message := Message{
|
||||||
// Index: rowIndex,
|
// Index: rowIndex,
|
||||||
Name: strings.TrimSpace(rec[FIELD_NAME]),
|
Name: strings.TrimSpace(rec[FIELD_NAME]),
|
||||||
Number: strings.TrimSpace(rec[FIELD_PHONE]),
|
Number: strings.TrimSpace(rec[FIELD_PHONE]),
|
||||||
@ -86,20 +110,17 @@ func (cfg *MainConfig) LaxParseCSV(csvr *csv.Reader) (messages []smsgw.Message,
|
|||||||
Vars: vars,
|
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)
|
messages = append(messages, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
return messages, warns, nil
|
return messages, warns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetFieldIndex(header []string, name string) int {
|
||||||
|
for i, h := range header {
|
||||||
|
if strings.EqualFold(strings.TrimSpace(h), name) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
@ -5,19 +5,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Gateway interface {
|
|
||||||
CurlString(to, text string) string
|
|
||||||
Send(to, text string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Message struct {
|
|
||||||
Name string
|
|
||||||
Number string
|
|
||||||
Template string
|
|
||||||
Vars map[string]string
|
|
||||||
Text string
|
|
||||||
}
|
|
||||||
|
|
||||||
var ErrInvalidClockFormat = fmt.Errorf("invalid clock time, ex: '06:00 PM', '6pm', or '18:00' (space and case insensitive)")
|
var ErrInvalidClockFormat = fmt.Errorf("invalid clock time, ex: '06:00 PM', '6pm', or '18:00' (space and case insensitive)")
|
||||||
var ErrInvalidClockTime = fmt.Errorf("invalid hour or minute, for example '27:63 p' would not be valid")
|
var ErrInvalidClockTime = fmt.Errorf("invalid hour or minute, for example '27:63 p' would not be valid")
|
||||||
var ErrPhoneEmpty = fmt.Errorf("no phone number")
|
var ErrPhoneEmpty = fmt.Errorf("no phone number")
|
||||||
@ -25,6 +12,11 @@ var ErrPhoneInvalid11 = fmt.Errorf("invalid 11-digit number (does not start with
|
|||||||
var ErrPhoneInvalid12 = fmt.Errorf("invalid 12-digit number (does not start with +1)")
|
var ErrPhoneInvalid12 = fmt.Errorf("invalid 12-digit number (does not start with +1)")
|
||||||
var ErrPhoneInvalidLength = fmt.Errorf("invalid number length (should be 10 digits or 12 with +1 prefix)")
|
var ErrPhoneInvalidLength = fmt.Errorf("invalid number length (should be 10 digits or 12 with +1 prefix)")
|
||||||
|
|
||||||
|
type Gateway interface {
|
||||||
|
CurlString(to, text string) string
|
||||||
|
Send(to, text string) error
|
||||||
|
}
|
||||||
|
|
||||||
// Strips away symbols, non-printing characters copied from HTML, etc,
|
// Strips away symbols, non-printing characters copied from HTML, etc,
|
||||||
// leaving only a possible leading '+' and digits.
|
// leaving only a possible leading '+' and digits.
|
||||||
// Does not leave *, # or comma.
|
// Does not leave *, # or comma.
|
||||||
|
|||||||
@ -8,11 +8,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/therootcompany/golib/net/smsgw"
|
"github.com/therootcompany/golib/net/smsgw"
|
||||||
|
"github.com/therootcompany/golib/net/smsgw/smscsv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var reUnmatchedVars = regexp.MustCompile(`(\{[^}]+\})`)
|
var reUnmatchedVars = regexp.MustCompile(`(\{[^}]+\})`)
|
||||||
|
|
||||||
func RenderMessages(messages []smsgw.Message) ([]smsgw.Message, error) {
|
func RenderAll(messages []smscsv.Message) ([]smscsv.Message, error) {
|
||||||
|
var err error
|
||||||
|
var warns []smscsv.CSVWarn
|
||||||
|
|
||||||
for i, message := range messages {
|
for i, message := range messages {
|
||||||
rowIndex := i + 1
|
rowIndex := i + 1
|
||||||
|
|
||||||
@ -24,8 +28,20 @@ func RenderMessages(messages []smsgw.Message) ([]smsgw.Message, error) {
|
|||||||
message.Text = ReplaceVar(message.Text, key, val)
|
message.Text = ReplaceVar(message.Text, key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message.Number = smsgw.StripFormatting(message.Number)
|
||||||
|
message.Number, err = smsgw.PrefixUS10Digit(message.Number)
|
||||||
|
if err != nil {
|
||||||
|
warns = append(warns, smscsv.CSVWarn{
|
||||||
|
Index: rowIndex,
|
||||||
|
Code: "PhoneInvalid",
|
||||||
|
Message: fmt.Sprintf("ignoring row %d (%s): %s", rowIndex, message.Name, err.Error()),
|
||||||
|
// Record: rec,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if tmpls := reUnmatchedVars.FindAllString(message.Text, -1); len(tmpls) != 0 {
|
if tmpls := reUnmatchedVars.FindAllString(message.Text, -1); len(tmpls) != 0 {
|
||||||
return nil, &CSVWarn{
|
return nil, &smscsv.CSVWarn{
|
||||||
Index: rowIndex,
|
Index: rowIndex,
|
||||||
Code: "UnmatchedVars",
|
Code: "UnmatchedVars",
|
||||||
Message: fmt.Sprintf(
|
Message: fmt.Sprintf(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user