package twilio import ( "net/url" "strconv" "strings" "time" ) // ErrInvalidMessage is returned when a bad message is sent to the Twilio // receive hook; it tries to clarify why the message is invalid. type ErrInvalidMessage struct { missing []string cause string } // Error satisfies the error interface. func (err *ErrInvalidMessage) Error() string { errParts := []string{} if len(err.missing) > 0 { errParts = append(errParts, "missing="+strings.Join(err.missing, ",")) } if err.cause != "" { errParts = append(errParts, "cause="+err.cause) } return strings.Join(errParts, ", ") } // isInvalidMessage returns an error given a list of missing fields and an // underlying cause, returning nil if the message is valid. func isInvalidMessage(missing []string, cause string) error { if len(missing) == 0 && cause == "" { return nil } return &ErrInvalidMessage{ missing: missing, cause: cause, } } // Message represents an incoming Twilio message. type Message struct { Source string To string Body string When time.Time MediaURL string ASID string MSID string Price float64 Mime string } // MessageFromValues returns a Message from a set of form values. func MessageFromValues(v url.Values) (*Message, error) { missing := []string{} cause := "" m := &Message{ Source: v.Get("From"), To: v.Get("To"), Body: v.Get("Body"), MediaURL: v.Get("MediaUrl0"), ASID: v.Get("AccountSid"), MSID: v.Get("MessageSid"), When: time.Now().UTC(), Price: 0.0075, } if m.Source == "" { missing = append(missing, "From") } if m.To == "" { missing = append(missing, "To") } numMediaValue := v.Get("NumMedia") if numMediaValue == "" { numMediaValue = "0" } nMedia, err := strconv.Atoi(numMediaValue) if err != nil { return nil, err } if nMedia == 0 && m.Body == "" { cause = "message has no body or media attachment" } else if nMedia != 0 { if m.MediaURL == "" { missing = append(missing, "MediaUrl0") } m.Price = 0.01 if m.Mime = v.Get("MediaContentType0"); m.Mime == "" { missing = append(missing, "MediaContentType0") } } if sent := v.Get("DateSent"); sent != "" { t, err := time.Parse(time.RFC1123Z, sent) if err != nil { return nil, err } m.When = t.UTC() } if err := isInvalidMessage(missing, cause); err != nil { return nil, err } return m, nil }