From 681005f10e7dc421b986faa6917b443913cf8851 Mon Sep 17 00:00:00 2001 From: Joerg Lehmann Date: Wed, 20 Jul 2022 17:49:07 +0200 Subject: [PATCH] refactor email send functions, integrate check_nodes in mini-beieli-web --- check_mini_beieli_nodes/main.go | 399 -------------------------------- check_nodes.go | 130 +++++++++++ go.mod | 11 + go.sum | 29 +++ helper.go | 9 + mail.go | 63 +++-- main.go | 1 + persistence.go | 38 ++- 8 files changed, 245 insertions(+), 435 deletions(-) delete mode 100644 check_mini_beieli_nodes/main.go create mode 100644 check_nodes.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/check_mini_beieli_nodes/main.go b/check_mini_beieli_nodes/main.go deleted file mode 100644 index c0439b0..0000000 --- a/check_mini_beieli_nodes/main.go +++ /dev/null @@ -1,399 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "fmt" - "github.com/gomodule/redigo/redis" - "github.com/jordan-wright/email" - "io/ioutil" - "log" - "net/http" - "os" - "strconv" - "strings" - "time" -) - -func sendEmailAccu(username string, alias string, deveui string, accu_percent string, threshold int, level string) { - fmt.Printf("SEND EMAIL ACCU (%s) - %s:%s\n", level, username, deveui) - mail_message := `Lieber Benutzer von mini-beieli.ch - -Der Akku von "` + alias + `" (DevEUI: ` + deveui + `) ist noch zu ` + accu_percent + ` Prozent geladen. - -Bitte rechtzeitig wieder laden! Bei 10%-er Ladung erscheint die letzte Warnung. - -Mit freundlichen Grüssen --- -mini-beieli.ch` - - e := email.NewEmail() - e.From = "mini-beieli.ch " - e.To = []string{username} - e.Bcc = []string{"joerg.lehmann@nbit.ch"} - e.Subject = level + " - mini-beieli.ch: Akku Ladezustand (" + alias + ")" - e.Text = []byte(mail_message) - e.Send("127.0.0.1:25", nil) -} - -func sendEmailAbo(username string, alias string, deveui string, days_left int, level string) { - fmt.Printf("SEND EMAIL ABO (%s) - %s:%s\n", level, username, deveui) - mail_message := `Lieber Benutzer von mini-beieli.ch - -Das Abo von "` + alias + `" (DevEUI: ` + deveui + `) laeuft in ` + strconv.Itoa(days_left) + ` Tagen ab. - -Bitte Abo verlaengern auf https://mini-beieli.ch - -Mit freundlichen Grüssen --- -mini-beieli.ch` - - e := email.NewEmail() - e.From = "mini-beieli.ch " - e.To = []string{username} - e.Bcc = []string{"joerg.lehmann@nbit.ch"} - e.Subject = level + " - mini-beieli.ch: Abo laeuft ab (" + alias + ")" - e.Text = []byte(mail_message) - e.Send("127.0.0.1:25", nil) -} - -var globalPool *redis.Pool - -const userPrefix string = "user:" -const devPrefix string = "dev:" -const confirmPrefix string = "confirm:" - -func newPool() *redis.Pool { - return &redis.Pool{ - // Maximum number of idle connections in the pool. - MaxIdle: 80, - // max number of connections - MaxActive: 12000, - // Dial is an application supplied function for creating and - // configuring a connection. - Dial: func() (redis.Conn, error) { - c, err := redis.Dial("tcp", ":6379") - if err != nil { - panic(err.Error()) - } - return c, err - }, - } -} - -// ping tests connectivity for redis (PONG should be returned) -func ping(c redis.Conn) error { - // Send PING command to Redis - // PING command returns a Redis "Simple String" - // Use redis.String to convert the interface type to string - s, err := redis.String(c.Do("PING")) - if err != nil { - return err - } - - logit("PING Response = " + s) - // Output: PONG - - return nil -} - -type Dev struct { - Deveui string - Alias string - Alarmactive string - Smsnumber string - ActiveUntil string // Abo bezahlt bis TT.MM.YYYY -} - -func initDB() { - - // newPool returns a pointer to a redis.Pool - pool := newPool() - // get a connection from the globalPool (redis.Conn) - conn := pool.Get() - defer conn.Close() - - globalPool = pool - - // wir machen einen Connection Test - ping(conn) -} - -func closeDB() { - globalPool.Close() -} - -func getUsers() []string { - res := []string{} - - conn := globalPool.Get() - defer conn.Close() - - //logit("getUsers") - users, err := redis.Strings(conn.Do("KEYS", userPrefix+"*")) - if err == nil { - //logit("getUsers successful!") - res = users - } else { - log.Print(err) - } - - return res -} - -func getMyDevs(username string) []string { - res := []string{} - - if username == "" { - return res - } - - conn := globalPool.Get() - defer conn.Close() - - //logit("getMyDevs: User: " + username) - mydevs, err := redis.String(conn.Do("HGET", userPrefix+username, "my_devs")) - if err == nil { - //logit("getMyDevs: mydevs: " + mydevs) - res = strings.Split(mydevs, ",") - } else { - log.Print(err) - } - - return res -} - -func getDevAlias(deveui string) string { - res := deveui - - if deveui == "" { - return res - } - - conn := globalPool.Get() - defer conn.Close() - - //logit("getDevAlias: Deveui: " + deveui) - alias, err := redis.String(conn.Do("HGET", devPrefix+deveui, "alias")) - if err == nil { - //logit("getDevAlias: alias: " + alias) - res = alias - } else { - log.Print(err) - } - - return res -} - -func getActiveUntil(deveui string) string { - res := "" - - if deveui == "" { - return res - } - - conn := globalPool.Get() - defer conn.Close() - - //logit("getActiveUntil: Deveui: " + deveui) - activeuntil, err := redis.String(conn.Do("HGET", devPrefix+deveui, "active_until")) - if err == nil { - //logit("getActiveUntil: activeuntil: " + activeuntil) - res = activeuntil - } else { - log.Print(err) - } - - return res -} - -func InsertAlert(prefix string, deveui string, email string, threshold int) { - conn := globalPool.Get() - defer conn.Close() - - _, err := conn.Do("SET", prefix+deveui+":"+email, threshold) - if err != nil { - logit("InsertAlert: Error inserting: " + prefix + deveui + ":" + email) - } -} - -func DeleteAlert(prefix string, deveui string, email string) { - conn := globalPool.Get() - defer conn.Close() - - exists, _ := redis.Bool(conn.Do("EXISTS", prefix+deveui+":"+email)) - - if exists { - _, err := conn.Do("DEL", prefix+deveui+":"+email) - if err != nil { - logit("DeleteAlert: Error deleting: " + prefix + deveui + ":" + email) - } - } -} - -func AlarmNotAlreadySent(prefix string, deveui string, email string, threshold int) bool { - conn := globalPool.Get() - defer conn.Close() - - exists, _ := redis.Bool(conn.Do("EXISTS", prefix+deveui+":"+email)) - if !exists { - return true - } - alarm_threshold, _ := redis.Int(conn.Do("GET", prefix+deveui+":"+email)) - return threshold != alarm_threshold -} - -type OneMetric struct { - Deveui string - Alias string - Timestamp string - BatteryPercent string - ActiveUntil string - DaysUntilDeactivated int // berechneter Wert -} - -func CalcDaysUntil(mydate string) int { - var days int - layout := "02.01.2006" - t, err := time.Parse(layout, mydate) - - if err != nil { - days = 0 - } - days = int(t.Sub(time.Now()).Hours() / 24) - - return days -} - -func getLastMetrics(deveui string) OneMetric { - var res OneMetric - - url := "http://localhost:8086/api/v2/query?org=minibeieliorg" - data := []byte(fmt.Sprintf(`from(bucket:"minibeielibucket") - |> range(start:-5d) - |> filter(fn: (r) => r._measurement == "measurement" and r.deveui == "%s") - |> filter(fn: (r) => r._field == "vp") - |> last(column: "_time") |> yield(name: "last")`, deveui)) - - req, err := http.NewRequest("POST", url, bytes.NewBuffer(data)) - if err != nil { - log.Fatal("Error reading request. ", err) - } - - // Set headers - var INFLUX_RO_TOKEN = os.Getenv("INFLUX_RO_TOKEN") - - // Set headers - req.Header.Set("Authorization", "Token "+INFLUX_RO_TOKEN) - req.Header.Set("accept", "application/csv") - req.Header.Set("content-type", "application/vnd.flux") - - // Set client timeout - client := &http.Client{Timeout: time.Second * 10} - - // Send request - resp, err := client.Do(req) - if err != nil { - log.Fatal("Error reading response. ", err) - } - defer resp.Body.Close() - - //fmt.Println("response Status:", resp.Status) - //fmt.Println("response Headers:", resp.Header) - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Fatal("Error reading body. ", err) - } - //fmt.Println("response Body:", string(body)) - - scanner := bufio.NewScanner(strings.NewReader(string(body))) - location, err := time.LoadLocation("Europe/Zurich") - for scanner.Scan() { - s := strings.Split(scanner.Text(), ",") - if (len(s) >= 7) && !(strings.HasPrefix(s[5], "_")) { - mytime, err := time.Parse(time.RFC3339, s[5]) - if err != nil { - continue - } - res.Timestamp = mytime.In(location).Format("02.01.2006 15:04") - value := s[6] - field := s[7] - if field == "vp" { - res.BatteryPercent = value - } - } - } - res.Deveui = deveui - res.Alias = getDevAlias(deveui) - res.ActiveUntil = getActiveUntil(deveui) - res.DaysUntilDeactivated = CalcDaysUntil(res.ActiveUntil) - return res -} - -func CheckThreshold(d string, vp int, u2 string, last_metric OneMetric, info_threshold int, warning_threshold int, alert_threshold int) bool { - var alias string - if vp <= info_threshold { - alias = getDevAlias(d) - } - if vp <= alert_threshold { - if AlarmNotAlreadySent("alarm_sent_accu:", d, u2, alert_threshold) { - sendEmailAccu(u2, alias, d, last_metric.BatteryPercent, alert_threshold, "ALARM") - InsertAlert("alarm_sent_accu:", d, u2, alert_threshold) - } - return false - } - if vp <= warning_threshold { - if AlarmNotAlreadySent("alarm_sent_accu:", d, u2, warning_threshold) { - sendEmailAccu(u2, alias, d, last_metric.BatteryPercent, warning_threshold, "WARNING") - InsertAlert("alarm_sent_accu:", d, u2, warning_threshold) - } - return false - } - if vp <= info_threshold { - if AlarmNotAlreadySent("alarm_sent_accu:", d, u2, info_threshold) { - sendEmailAccu(u2, alias, d, last_metric.BatteryPercent, alert_threshold, "INFO") - InsertAlert("alarm_sent_accu:", d, u2, info_threshold) - } - return false - } - return true -} - -func logit(log_message string) { - log.Println(log_message) -} - -func main() { - logit("Starting check_battery...") - initDB() - defer closeDB() - - users := getUsers() - for _, u := range users { - //fmt.Println(u) - u2 := u[5:] - my_devs := getMyDevs(u2) - for _, d := range my_devs { - //fmt.Printf("%s:%s\n", u2, d) - if !strings.HasPrefix(d, "@") { - last_metric := getLastMetrics(d) - // Zuerst der Batteriealarm - if last_metric.BatteryPercent != "" { - fmt.Printf("%s:%s:%s Percent:%s:%d\n", u2, d, last_metric.BatteryPercent, last_metric.ActiveUntil, last_metric.DaysUntilDeactivated) - vp, _ := strconv.Atoi(last_metric.BatteryPercent) - if CheckThreshold(d, vp, u2, last_metric, 50, 20, 10) { - DeleteAlert("alarm_sent_accu:", d, u2) - } - } - // Jetzt der Alarm wegen der Abodauer - if last_metric.DaysUntilDeactivated < 30 { - fmt.Printf("SEND EMAIL %s:%s:%s Percent:%s:%d\n", u2, d, last_metric.BatteryPercent, last_metric.ActiveUntil, last_metric.DaysUntilDeactivated) - alias := getDevAlias(d) - sendEmailAbo("joerg.lehmann@nbit.ch", alias, d, last_metric.DaysUntilDeactivated, "INFO") - } - } - } - } - logit("Done with check_battery...") -} diff --git a/check_nodes.go b/check_nodes.go new file mode 100644 index 0000000..de86c7a --- /dev/null +++ b/check_nodes.go @@ -0,0 +1,130 @@ +package main + +import ( + "fmt" + "net/http" + "strconv" + "strings" +) + +func sendEmailAccu(username string, alias string, deveui string, accu_percent string, threshold int, level string) { + fmt.Printf("SEND EMAIL ACCU (%s) - %s:%s\n", level, username, deveui) + mail_message := "To: " + username + ` +From: info@mini-beieli.ch +Subject: ` + level + ` - mini-beieli.ch: Akku Ladezustand (` + alias + `) + +Lieber Benutzer von mini-beieli.ch + +Der Akku von "` + alias + `" (DevEUI: ` + deveui + `) ist noch zu ` + accu_percent + ` Prozent geladen. + +Bitte rechtzeitig wieder laden! Bei Unterschreitung von 5% Ladung erscheint die letzte Warnung. + +Mit freundlichen Grüssen +-- +mini-beieli.ch` + + sendEmail(username, "mail@mini-beieli.ch", mail_message) +} + +func sendEmailAbo(username string, alias string, deveui string, days_left int, level string) { + var ablauftext string + if days_left == 0 { + fmt.Printf("SEND EMAIL ABO (%s) - %s:%s\n", level, username, deveui) + ablauftext = "Das Abo von \"" + alias + "\" (DevEUI: " + deveui + ") ist abgelaufen." + } else if days_left > 0 { + fmt.Printf("SEND EMAIL ABO (%s) - %s:%s\n", level, username, deveui) + ablauftext = "Das Abo von \"" + alias + "\" (DevEUI: " + deveui + ") laeuft in " + strconv.Itoa(days_left) + " Tagen ab." + } else { + fmt.Printf("DO NOT SEND EMAIL ABO (%s) - %s:%s\n", level, username, deveui) + return + } + mail_message := "To: " + username + ` +From: info@mini-beieli.ch +Subject: ` + level + ` - mini-beieli.ch: Abo verlaengern (` + alias + `) + +Lieber Benutzer von mini-beieli.ch + +` + ablauftext + ` + +Bitte Abo verlaengern auf https://mini-beieli.ch + +Mit freundlichen Grüssen +-- +mini-beieli.ch` + + sendEmail(username, "mail@mini-beieli.ch", mail_message) +} + +func CheckThreshold(d string, vp int, u2 string, last_metric OneMetric, info_threshold int, warning_threshold int, alert_threshold int) bool { + var alias string + if vp <= info_threshold { + alias = getDevAlias(d) + } + if vp <= alert_threshold { + if AlarmNotAlreadySent("alarm_sent_accu:", d, u2, alert_threshold) { + sendEmailAccu(u2, alias, d, last_metric.BatteryPercent, alert_threshold, "ALARM") + InsertAlert("alarm_sent_accu:", d, u2, alert_threshold) + } + return false + } + if vp <= warning_threshold { + if AlarmNotAlreadySent("alarm_sent_accu:", d, u2, warning_threshold) { + sendEmailAccu(u2, alias, d, last_metric.BatteryPercent, warning_threshold, "WARNING") + InsertAlert("alarm_sent_accu:", d, u2, warning_threshold) + } + return false + } + if vp <= info_threshold { + if AlarmNotAlreadySent("alarm_sent_accu:", d, u2, info_threshold) { + sendEmailAccu(u2, alias, d, last_metric.BatteryPercent, alert_threshold, "INFO") + InsertAlert("alarm_sent_accu:", d, u2, info_threshold) + } + return false + } + return true +} + +func checkNodes() { + logit("Starting check_battery...") + + users := getUsers() + for _, u := range users { + //fmt.Println(u) + u2 := u[5:] + my_devs := getMyDevs(u2) + for _, d := range my_devs { + fmt.Printf("%s:%s\n", u2, d) + if !strings.HasPrefix(d, "@") { + last_metric := getLastMetrics(d) + // Zuerst der Batteriealarm + if last_metric.BatteryPercent != "" { + fmt.Printf("%s:%s:%s Percent:%s:%d\n", u2, d, last_metric.BatteryPercent, last_metric.ActiveUntil, last_metric.DaysUntilDeactivated) + vp, _ := strconv.Atoi(last_metric.BatteryPercent) + if CheckThreshold(d, vp, u2, last_metric, 20, 10, 5) { + DeleteAlert("alarm_sent_accu:", d, u2) + } + } + // Jetzt der Alarm wegen der Abodauer + if last_metric.DaysUntilDeactivated < 30 { + fmt.Printf("SEND EMAIL %s:%s:%s Percent:%s:%d\n", u2, d, last_metric.BatteryPercent, last_metric.ActiveUntil, last_metric.DaysUntilDeactivated) + alias := getDevAlias(d) + sendEmailAbo(u2, alias, d, last_metric.DaysUntilDeactivated, "INFO") + } + } + } + } + logit("Done with check_battery...") +} + +func checkNodesHandler(w http.ResponseWriter, req *http.Request) { + headers := req.Header + + val, ok := headers["X-Checknodes"] + if ok { + fmt.Printf("X-Checknodes header is present with value %s\n", val) + checkNodes() + } else { + fmt.Println("X-Checknodes header is not present") + } + w.WriteHeader(http.StatusOK) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c6bc817 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module nbit.ch/mini-beieli-web/v2 + +go 1.17 + +require ( + github.com/gomodule/redigo v1.8.9 + github.com/gorilla/securecookie v1.1.1 + github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible + github.com/stripe/stripe-go v70.15.0+incompatible + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..872a20d --- /dev/null +++ b/go.sum @@ -0,0 +1,29 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= +github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA= +github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stripe/stripe-go v70.15.0+incompatible h1:hNML7M1zx8RgtepEMlxyu/FpVPrP7KZm1gPFQquJQvM= +github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helper.go b/helper.go index 1a3737f..4bbec7b 100644 --- a/helper.go +++ b/helper.go @@ -2,6 +2,7 @@ package main import ( "log" + "os" ) // Contains tells whether a contains x. @@ -18,3 +19,11 @@ func Contains(a []string, x string) bool { } return false } + +func getenv(key, fallback string) string { + value := os.Getenv(key) + if len(value) == 0 { + return fallback + } + return value +} diff --git a/mail.go b/mail.go index a24673d..9db7750 100644 --- a/mail.go +++ b/mail.go @@ -1,27 +1,39 @@ package main import ( - "bytes" "log" "net/smtp" ) -func sendEmail(username, confirm_id string) { - c, err := smtp.Dial("127.0.0.1:25") +func sendEmail(mail_to, mail_default_authuser, mail_message string) { + var auth smtp.Auth + if getenv("MAILSERVER_USER", "") != "" { + // Set up authentication information. + auth = smtp.PlainAuth( + "", + getenv("MAILSERVER_USER", ""), + getenv("MAILSERVER_PASSWORD", ""), + getenv("MAILSERVER_HOST", "127.0.0.1"), + ) + } + // Connect to the server, authenticate, set the sender and recipient, + // and send the email all in one step. + err := smtp.SendMail( + getenv("MAILSERVER_HOST", "127.0.0.1")+":"+getenv("MAILSERVER_PORT", "25"), + auth, + getenv("MAILSERVER_USER", mail_default_authuser), + []string{mail_to, "info@mini-beieli.ch"}, + []byte(mail_message), + ) + if err != nil { log.Fatal(err) } - defer c.Close() - // Set the sender and recipient. - c.Mail("register@mini-beieli.ch") - c.Rcpt(username) - // Send the email body. - wc, err := c.Data() - if err != nil { - log.Fatal(err) - } - defer wc.Close() +} + +func sendEmailConfirm(username, confirm_id string) { mail_message := "To: " + username + ` +From: register@mini-beieli.ch Subject: Passwortaenderung auf https://mini-beieli.ch, bitte bestaetigen Lieber Benutzer von mini-beieli.ch @@ -37,28 +49,12 @@ Mit freundlichen Grüssen -- mini-beieli.ch` - buf := bytes.NewBufferString(mail_message) - if _, err = buf.WriteTo(wc); err != nil { - log.Fatal(err) - } + sendEmail(username, "mail@mini-beieli.ch", mail_message) } func sendPaymentConfirmationEmail(username, charge_data string, amount int64) { - c, err := smtp.Dial("127.0.0.1:25") - if err != nil { - log.Fatal(err) - } - defer c.Close() - // Set the sender and recipient. - c.Mail("info@mini-beieli.ch") - c.Rcpt(username) - // Send the email body. - wc, err := c.Data() - if err != nil { - log.Fatal(err) - } - defer wc.Close() mail_message := "To: " + username + ` +From: info@mini-beieli.ch Subject: Zahlungsbestaetigung mini-beieli.ch Lieber Benutzer von mini-beieli.ch @@ -71,8 +67,5 @@ Mit freundlichen Grüssen -- mini-beieli.ch` - buf := bytes.NewBufferString(mail_message) - if _, err = buf.WriteTo(wc); err != nil { - log.Fatal(err) - } + sendEmail(username, "mail@mini-beieli.ch", mail_message) } diff --git a/main.go b/main.go index 251998d..b57175a 100644 --- a/main.go +++ b/main.go @@ -99,6 +99,7 @@ func main() { http.HandleFunc("/save_scale_settings", save_scale_settingsHandler) http.HandleFunc("/getstripepaymentintent", getstripepaymentintentHandler) http.HandleFunc("/stripewebhook", stripeWebhookHandler) + http.HandleFunc("/checknodes", checkNodesHandler) logit("Starting Web Application...") http.ListenAndServe("127.0.0.1:4000", nil) diff --git a/persistence.go b/persistence.go index b0ccd97..7e2f6af 100644 --- a/persistence.go +++ b/persistence.go @@ -385,7 +385,7 @@ func updateUser(username, password string) { return } - sendEmail(username, confirm_id) + sendEmailConfirm(username, confirm_id) } func checkLoginCredentials(username, password string) bool { @@ -454,3 +454,39 @@ func confirmUser(confirm_id string) bool { return true } + +func InsertAlert(prefix string, deveui string, email string, threshold int) { + conn := globalPool.Get() + defer conn.Close() + + _, err := conn.Do("SET", prefix+deveui+":"+email, threshold) + if err != nil { + logit("InsertAlert: Error inserting: " + prefix + deveui + ":" + email) + } +} + +func DeleteAlert(prefix string, deveui string, email string) { + conn := globalPool.Get() + defer conn.Close() + + exists, _ := redis.Bool(conn.Do("EXISTS", prefix+deveui+":"+email)) + + if exists { + _, err := conn.Do("DEL", prefix+deveui+":"+email) + if err != nil { + logit("DeleteAlert: Error deleting: " + prefix + deveui + ":" + email) + } + } +} + +func AlarmNotAlreadySent(prefix string, deveui string, email string, threshold int) bool { + conn := globalPool.Get() + defer conn.Close() + + exists, _ := redis.Bool(conn.Do("EXISTS", prefix+deveui+":"+email)) + if !exists { + return true + } + alarm_threshold, _ := redis.Int(conn.Do("GET", prefix+deveui+":"+email)) + return threshold != alarm_threshold +}