func (server TwilioSMSCallbackServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { periwinkle.Logf("TwilioCallback") fmt.Fprintf(w, "Hi there, I love %s!", req.URL.String()) body, err := ioutil.ReadAll(req.Body) if err != nil { periwinkle.LogErr(locale.UntranslatedError(err)) return } values, err := url.ParseQuery(string(body)) if err != nil { periwinkle.LogErr(locale.UntranslatedError(err)) return } status := backend.TwilioSMSMessage{ MessageStatus: values.Get("MessageStatus"), ErrorCode: values.Get("ErrorCode"), MessageSID: values.Get("MessageSid"), } server.DB.Do(func(db *periwinkle.Tx) { status.Save(db) }) }
// Diff two objects, and produce an RFC 6902 JSON Patch. func NewJSONPatch(a interface{}, b interface{}) (jsonpatch.JSONPatch, locale.Error) { // convert a to json aBytes, uerr := json.Marshal(a) if uerr != nil { return nil, locale.UntranslatedError(uerr) } // convert b to json bBytes, uerr := json.Marshal(b) if uerr != nil { return nil, locale.UntranslatedError(uerr) } // diff them p, uerr := matt.CreatePatch(aBytes, bBytes) if uerr != nil { return nil, locale.UntranslatedError(uerr) } pBytes, uerr := json.Marshal(p) if uerr != nil { return nil, locale.UntranslatedError(uerr) } // return var ret jsonpatch.JSONPatch uerr = json.Unmarshal(pBytes, &ret) return ret, locale.UntranslatedError(uerr) }
// DecoderFormData maps multipart/form-data => json.Decoder # because fuckit func DecoderFormData(r io.Reader, params map[string]string) (interface{}, locale.Error) { boundary, ok := params["boundary"] if !ok { return nil, locale.UntranslatedError(http.ErrMissingBoundary) } reader := multipart.NewReader(r, boundary) form, uerr := reader.ReadForm(0) if uerr != nil { return nil, locale.UntranslatedError(uerr) } entity := make(map[string]interface{}, len(form.Value)+len(form.File)) for k, v := range form.Value { entity[k] = v } for k, v := range form.File { if _, exists := entity[k]; exists { values := entity[k].([]string) list := make([]interface{}, len(values)+len(v)) i := uint(0) for _, value := range values { list[i] = value i++ } for _, value := range v { list[i] = value i++ } entity[k] = list } else { entity[k] = v } } return fuckitJSON(entity) }
func DeleteUnusedTwilioNumber(db *periwinkle.Tx, num string) locale.Error { var twilioNum TwilioNumber if result := db.Where("number = ?", num).First(&twilioNum); result.Error != nil { if result.RecordNotFound() { periwinkle.Logf("The number is already deleted!!!") return nil } dbError(result.Error) return locale.UntranslatedError(result.Error) } var twilioPool TwilioPool result := db.Where("number_id = ?", twilioNum.ID).First(&twilioPool) if result.Error != nil { if result.RecordNotFound() { o := db.Where("number = ?", num).Delete(&TwilioNumber{}) if o.Error != nil { dbError(o.Error) return locale.UntranslatedError(o.Error) } periwinkle.Logf("The number is deleted") return nil } dbError(result.Error) return locale.UntranslatedError(result.Error) } periwinkle.Logf("The number is used for a twilio pool") return nil }
func (l NetJSON) Write(w io.Writer, loc locale.Spec) locale.Error { bytes, uerr := json.Marshal(l.Data) if uerr != nil { return locale.UntranslatedError(uerr) } _, uerr = w.Write(bytes) return locale.UntranslatedError(uerr) }
func (e EncoderJSONStr) Write(w io.Writer, l locale.Spec) locale.Error { bytes, err := json.Marshal(e.Data.L10NString(l)) if err != nil { return locale.UntranslatedError(err) } _, err = w.Write(bytes) return locale.UntranslatedError(err) }
func (o Medium) dbSeed(db *periwinkle.Tx) locale.Error { errs := errorList{} errHelper(&errs, locale.UntranslatedError(db.Create(&Medium{"email"}).Error)) errHelper(&errs, locale.UntranslatedError(db.Create(&Medium{"sms"}).Error)) errHelper(&errs, locale.UntranslatedError(db.Create(&Medium{"mms"}).Error)) if len(errs) > 0 { return errs } return nil }
func checkNumber(config *periwinkle.Cfg, tx *periwinkle.Tx, number backend.TwilioNumber) { url := "https://api.twilio.com/2010-04-01/Accounts/" + config.TwilioAccountID + "/Messages.json?To=" + number.Number if lastPoll != timeZero { url += "&DateSent>=" + strings.Split(lastPoll.UTC().String(), " ")[0] } req, _ := http.NewRequest("GET", url, nil) req.SetBasicAuth(config.TwilioAccountID, config.TwilioAuthToken) resp, uerr := (&http.Client{}).Do(req) if uerr != nil { periwinkle.LogErr(locale.UntranslatedError(uerr)) } defer resp.Body.Close() body, uerr := ioutil.ReadAll(resp.Body) if uerr != nil { periwinkle.LogErr(locale.UntranslatedError(uerr)) } // converts JSON messages var page twilio.Paging json.Unmarshal([]byte(body), &page) for _, message := range page.Messages { timeSend, uerr := time.Parse(time.RFC1123Z, message.DateSent) if uerr != nil { periwinkle.LogErr(locale.UntranslatedError(uerr)) continue } if timeSend.Unix() < lastPoll.Unix() { periwinkle.Logf("message %q older than our last poll; ignoring", message.Sid) continue } user := backend.GetUserByAddress(tx, "sms", message.From) if user == nil { periwinkle.Logf("could not figure out which user has number %q", message.From) continue } group := backend.GetGroupByUserAndTwilioNumber(tx, user.ID, message.To) if group == nil { periwinkle.Logf("could not figure out which group this is meant for: user: %q, number: %q", user.ID, message.To) continue } periwinkle.Logf("received message for group %q", group.ID) MessageBuilder{ Maildir: config.Mailstore, Headers: map[string]string{ "To": group.ID + "@" + config.GroupDomain, "From": backend.UserAddress{Medium: "sms", Address: message.From}.AsEmailAddress(), "Subject": user.ID + ": " + message.Body, }, Body: "", }.Done() } }
// Apply the patch to an object; as if the object were // marshalled/unmarshalled JSON. func (patch JSONMergePatch) Apply(in interface{}, out interface{}) locale.Error { inBytes, uerr := json.Marshal(in) if uerr != nil { return locale.UntranslatedError(uerr) } outBytes, uerr := evan.MergePatch(inBytes, patch) if uerr != nil { return locale.UntranslatedError(uerr) } return locale.UntranslatedError(json.Unmarshal(outBytes, out)) }
// DecoderFormURLEncoded maps application/x-www-form-urlencoded => json.Decoder # because fuckit func DecoderFormURLEncoded(r io.Reader, params map[string]string) (interface{}, locale.Error) { bytes, uerr := ioutil.ReadAll(r) if uerr != nil { return nil, locale.UntranslatedError(uerr) } entity, uerr := url.ParseQuery(string(bytes)) if uerr != nil { return nil, locale.UntranslatedError(uerr) } return fuckitJSON(entity) }
func (l netLocationsJSON) Write(w io.Writer, loc locale.Spec) locale.Error { strs := make([]string, len(l.NetLocations)) for i, u := range l.NetLocations { strs[i] = u.String() } bytes, uerr := json.Marshal(strs) if uerr != nil { return locale.UntranslatedError(uerr) } _, uerr = w.Write(bytes) return locale.UntranslatedError(uerr) }
// DecoderJSONMergePatch maps application/merge-patch+json => jsonpatch.Patch func DecoderJSONMergePatch(r io.Reader, params map[string]string) (interface{}, locale.Error) { bytes, uerr := ioutil.ReadAll(r) if uerr != nil { return nil, locale.UntranslatedError(uerr) } var patch jsonpatch.JSONMergePatch uerr = json.Unmarshal(bytes, &patch) if uerr != nil { return nil, locale.UntranslatedError(uerr) } return jsonpatch.Patch(patch), nil }
func (l decodeJSONError) Write(w io.Writer, loc locale.Spec) locale.Error { data := map[string]interface{}{ "message": l.message.L10NString(loc), "diff": l.diff, } bytes, uerr := json.Marshal(data) if uerr != nil { return locale.UntranslatedError(uerr) } _, uerr = w.Write(bytes) return locale.UntranslatedError(uerr) }
func GetAllExistingTwilioNumbers(cfg *periwinkle.Cfg) []string { // gets url for the numbers we own in the Twilio Account incomingNumURL := "https://api.twilio.com/2010-04-01/Accounts/" + cfg.TwilioAccountID + "/IncomingPhoneNumbers.json" client := &http.Client{} req, err := http.NewRequest("GET", incomingNumURL, nil) if err != nil { periwinkle.LogErr(locale.UntranslatedError(err)) return nil } req.SetBasicAuth(cfg.TwilioAccountID, cfg.TwilioAuthToken) resp, err := client.Do(req) if err != nil { periwinkle.LogErr(locale.UntranslatedError(err)) return nil } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { periwinkle.LogErr(locale.UntranslatedError(err)) return nil } if resp.StatusCode != 200 { periwinkle.Logf("Response code %s", resp.Status) return nil } numbers := IncomingNumbers{} if err := json.Unmarshal(body, &numbers); err != nil { periwinkle.LogErr(locale.UntranslatedError(err)) return nil } if len(numbers.PhoneNumbers) > 0 { existingNumbers := make([]string, len(numbers.PhoneNumbers)) for i, num := range numbers.PhoneNumbers { existingNumbers[i] = num.Number } return existingNumbers } else { return nil } }
func fuckitJSON(entity interface{}) (interface{}, locale.Error) { str, uerr := json.Marshal(entity) if uerr != nil { return nil, locale.UntranslatedError(uerr) } return json.NewDecoder(strings.NewReader(string(str))), nil }
// Start the server; does not block. func (ss *HTTPServer) Start() { ss.Server.ConnState = ss.handleConnStateChange ss.wg.Add(1) go func() { defer ss.wg.Done() ss.err = locale.UntranslatedError(ss.Server.Serve(ss.Socket)) }() }
func (l netLocationsTXT) Write(w io.Writer, loc locale.Spec) locale.Error { for _, line := range l.NetLocations { _, uerr := fmt.Fprintln(w, line) if uerr != nil { return locale.UntranslatedError(uerr) } } return nil }
func DbDrop(db *periwinkle.Tx) locale.Error { errs := errorList{} for i := range tables { table := tables[len(tables)-1-i] errHelper(&errs, locale.UntranslatedError(db.DropTable(table).Error)) } if len(errs) > 0 { return errs } return nil }
// Panic, but a little nicer func dbError(err error) { // TODO: return better messages for Conflict errors. switch e := err.(type) { case sqlite3.Error: if e.Code == sqlite3.ErrConstraint { panic(periwinkle.Conflict{locale.UntranslatedError(e)}) } panic(locale.UntranslatedError(e)) case *mysql.MySQLError: // TODO: this list of error numbers might not be // complete, or totally correct. See // https://mariadb.com/kb/en/mariadb/mariadb-error-codes/ switch e.Number { case 1022, 1062, 1169, 1216, 1217, 1451, 1452, 1557, 1761, 1762, 1834: panic(periwinkle.Conflict{locale.UntranslatedError(e)}) } panic(locale.UntranslatedError(e)) default: panic(locale.Errorf("Programmer Error: the programmer said this is a database error, but it's not: %s", e)) } }
func OpenDB(driver, source string, debug bool) (*periwinkle.DB, locale.Error) { db, err := gorm.Open(driver, source) if err != nil && driver == "sqlite3" { err = db.Exec("PRAGMA foreign_keys = ON").Error db.DB().SetMaxOpenConns(1) } db.LogMode(debug) if err != nil { return nil, locale.UntranslatedError(err) } return periwinkle.NewDB(db), nil }
// Intro returns the envelope line insertet by Postfix before the RFC // 822-style message. func (pm *Message) Intro() (string, locale.Error) { if pm.stdin == nil { pm.stdin = bufio.NewReader(os.Stdin) } if pm.intro == nil { intro, err := pm.stdin.ReadString('\n') if err != nil { return "", locale.UntranslatedError(err) } pm.intro = &intro } return *pm.intro, nil }
func GetConfig(filename string) *periwinkle.Cfg { configFile, uerr := os.Open(filename) if uerr != nil { periwinkle.Logf("Could not open config file: %v", locale.UntranslatedError(uerr)) os.Exit(int(lsb.EXIT_NOTCONFIGURED)) } config, err := cfg.Parse(configFile) if err != nil { periwinkle.Logf("Could not parse config file: %v", err) os.Exit(int(lsb.EXIT_NOTCONFIGURED)) } return config }
func sdGetSocket() (socket net.Listener, err locale.Error) { fds := sd.ListenFds(true) if fds == nil { err = locale.Errorf("Failed to aquire sockets from systemd") return } if len(fds) != 1 { err = locale.Errorf("Wrong number of sockets from systemd: expected %d but got %d", 1, len(fds)) return } socket, uerr := net.FileListener(fds[0]) err = locale.UntranslatedError(uerr) fds[0].Close() return }
// Read an entity from the input stream, using the given content type. func (req *Request) readEntity(router *Router, reader io.Reader, contenttype string) *Response { mimetype, params, uerr := mime.ParseMediaType(contenttype) if uerr != nil { res := router.responseBadRequest(locale.Errorf("Could not parse Content-Type: %v", locale.UntranslatedError(uerr))) return &res } decoder, foundDecoder := router.Decoders[mimetype] if !foundDecoder { res := router.responseUnsupportedMediaType(locale.Errorf("Unsupported MIME type: " + mimetype)) return &res } entity, err := decoder(reader, params) if err != nil { res := router.responseUnsupportedMediaType(locale.Errorf("Error reading request body (%s): %v", mimetype, err)) return &res } req.Entity = entity return nil }
func (o Group) dbSeed(db *periwinkle.Tx) locale.Error { existence := [2]int{2, 2} read := [2]int{2, 2} post := [3]int{1, 1, 1} join := [3]int{1, 1, 1} return locale.UntranslatedError(db.Create(&Group{ ID: "test", ReadPublic: read[0], ReadConfirmed: read[1], ExistencePublic: existence[0], ExistenceConfirmed: existence[1], PostPublic: post[0], PostConfirmed: post[1], PostMember: post[2], JoinPublic: join[0], JoinConfirmed: join[1], JoinMember: join[2], Subscriptions: []Subscription{}, }).Error) }
func (accept accept) Acceptable(contenttype string) (bool, locale.Error) { mediafulltype, mediaparams, uerr := mime.ParseMediaType(contenttype) if uerr != nil { return false, locale.UntranslatedError(uerr) } mediatypeParts := strings.SplitN(mediafulltype, "/", 2) mediatype := mediatypeParts[0] mediasubtype := mediatypeParts[1] if accept.Type != mediatype && accept.Type != "*" { return false, nil } if accept.Subtype != mediasubtype && accept.Subtype != "*" { return false, nil } for key, acceptval := range accept.TypeParams { mediaval, ok := mediaparams[key] if !ok || mediaval != acceptval { return false, nil } } return true, nil }
func (o Medium) dbSchema(db *periwinkle.Tx) locale.Error { return locale.UntranslatedError(db.CreateTable(&o).Error) }
func (o UserAddress) dbSchema(db *periwinkle.Tx) locale.Error { return locale.UntranslatedError(db.CreateTable(&o). AddUniqueIndex("address_idx", "medium", "address"). //AddUniqueIndex("user_idx", "user_id", "sort_order"). Error) }
func (o Message) dbSchema(db *periwinkle.Tx) locale.Error { return locale.UntranslatedError(db.CreateTable(&o). AddUniqueIndex("filename_idx", "unique"). Error) }
func (o Subscription) dbSchema(db *periwinkle.Tx) locale.Error { return locale.UntranslatedError(db.CreateTable(&o).Error) }