package core
import (
"errors"
"fmt"
"net/smtp"
"strings"
"time"
"github.com/spf13/viper"
)
var notifiers = map [ string ] AbstractNotifier {
"email" : EmailNotifier { } ,
}
type AbstractNotifier interface {
New ( config interface { } ) ( AbstractNotifier , error )
ComposeNotification ( box * Box , checks [ ] CheckResult ) Notification
Submit ( notification Notification ) error
}
type Notification struct {
body string
subject string
}
// box config required for the EmailNotifier
type EmailNotifier struct {
Recipients [ ] string
}
func ( n EmailNotifier ) New ( config interface { } ) ( AbstractNotifier , error ) {
// assign configuration to the notifier after ensuring the correct type.
// lesson of this project: golang requires us to fuck around with type
// assertions, instead of providing us with proper inheritance.
asserted , ok := config . ( EmailNotifier )
if ! ok || asserted . Recipients == nil {
// config did not contain valid options.
// first try fallback: parse result of viper is a map[string]interface{},
// which requires a different assertion change
asserted2 , ok := config . ( map [ string ] interface { } )
if ok {
asserted3 , ok := asserted2 [ "recipients" ] . ( [ ] interface { } )
if ok {
asserted = EmailNotifier { Recipients : [ ] string { } }
for _ , rec := range asserted3 {
asserted . Recipients = append ( asserted . Recipients , rec . ( string ) )
}
}
}
if asserted . Recipients == nil {
return nil , errors . New ( "Invalid EmailNotifier options" )
}
}
return EmailNotifier {
Recipients : asserted . Recipients ,
} , nil
}
func ( n EmailNotifier ) ComposeNotification ( box * Box , checks [ ] CheckResult ) Notification {
resultTexts := [ ] string { }
for _ , check := range checks {
resultTexts = append ( resultTexts , check . String ( ) )
}
return Notification {
subject : fmt . Sprintf ( "Issues with your box \"%s\" on opensensemap.org!" , box . Name ) ,
body : fmt . Sprintf ( "A check at %s identified the following issue(s) with your box %s:\n\n%s\n\nYou may visit https://opensensemap.org/explore/%s for more details.\n\n--\nSent automatically by osem_notify (https://github.com/noerw/osem_notify)" ,
time . Now ( ) . Round ( time . Minute ) , box . Name , strings . Join ( resultTexts , "\n" ) , box . Id ) ,
}
}
func ( n EmailNotifier ) Submit ( notification Notification ) error {
auth := smtp . PlainAuth (
"" ,
viper . GetString ( "email.user" ) ,
viper . GetString ( "email.pass" ) ,
viper . GetString ( "email.host" ) ,
)
from := viper . GetString ( "email.from" )
body := fmt . Sprintf ( "From: openSenseMap Notifier <%s>\nSubject: %s\nContent-Type: text/plain; charset=\"utf-8\"\n\n%s" , from , notification . subject , notification . body )
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
err := smtp . SendMail (
fmt . Sprintf ( "%s:%s" , viper . GetString ( "email.host" ) , viper . GetString ( "email.port" ) ) ,
auth ,
from ,
n . Recipients ,
[ ] byte ( body ) ,
)
return err
}