# HG changeset patch # User Sascha L. Teichmann # Date 1545316409 -3600 # Node ID a0982c38eac0233e139401ebe63fad10e29224e7 # Parent 14bb1289b97b706327096efa2dafe25aee125dab Import queue: Implemented email notifications. diff -r 14bb1289b97b -r a0982c38eac0 pkg/controllers/bnimports.go --- a/pkg/controllers/bnimports.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/controllers/bnimports.go Thu Dec 20 15:33:29 2018 +0100 @@ -38,19 +38,18 @@ } var serialized string - serialized, err = common.ToJSONString(bn) - if err != nil { + if serialized, err = common.ToJSONString(bn); err != nil { return } session, _ := auth.GetSession(req) - jobID, err := imports.AddJob( + var jobID int64 + if jobID, err = imports.AddJob( imports.BNJobKind, session.User, - false, false, - serialized) - - if err != nil { + bi.SendEmail, false, + serialized, + ); err != nil { return } diff -r 14bb1289b97b -r a0982c38eac0 pkg/controllers/gmimports.go --- a/pkg/controllers/gmimports.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/controllers/gmimports.go Thu Dec 20 15:33:29 2018 +0100 @@ -30,28 +30,27 @@ conn *sql.Conn, ) (jr JSONResult, err error) { - bi := input.(*models.GaugeMeasurementImport) + gi := input.(*models.GaugeMeasurementImport) - bn := &imports.GaugeMeasurement{ - URL: bi.URL, - Insecure: bi.Insecure, + gm := &imports.GaugeMeasurement{ + URL: gi.URL, + Insecure: gi.Insecure, } var serialized string - serialized, err = common.ToJSONString(bn) - if err != nil { + if serialized, err = common.ToJSONString(gm); err != nil { return } session, _ := auth.GetSession(req) - jobID, err := imports.AddJob( + var jobID int64 + if jobID, err = imports.AddJob( imports.GMJobKind, session.User, - false, true, - serialized) - - if err != nil { + gi.SendEmail, true, + serialized, + ); err != nil { return } diff -r 14bb1289b97b -r a0982c38eac0 pkg/controllers/srimports.go --- a/pkg/controllers/srimports.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/controllers/srimports.go Thu Dec 20 15:33:29 2018 +0100 @@ -161,10 +161,12 @@ session, _ := auth.GetSession(req) + sendEmail := req.FormValue("bottleneck") != "" + jobID, err := imports.AddJob( imports.SRJobKind, session.User, - false, false, + sendEmail, false, serialized) if err != nil { diff -r 14bb1289b97b -r a0982c38eac0 pkg/imports/bn.go --- a/pkg/imports/bn.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/imports/bn.go Thu Dec 20 15:33:29 2018 +0100 @@ -79,6 +79,10 @@ RegisterJobCreator(BNJobKind, bnJobCreator{}) } +func (bnJobCreator) Description() string { + return "bottlenecks" +} + func (bnJobCreator) Create(_ JobKind, data string) (Job, error) { bn := new(Bottleneck) if err := common.FromJSONString(data, bn); err != nil { diff -r 14bb1289b97b -r a0982c38eac0 pkg/imports/gm.go --- a/pkg/imports/gm.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/imports/gm.go Thu Dec 20 15:33:29 2018 +0100 @@ -81,6 +81,10 @@ RegisterJobCreator(GMJobKind, gmJobCreator{}) } +func (gmJobCreator) Description() string { + return "gauge measurements" +} + func (gmJobCreator) Create(_ JobKind, data string) (Job, error) { gm := new(GaugeMeasurement) if err := common.FromJSONString(data, gm); err != nil { diff -r 14bb1289b97b -r a0982c38eac0 pkg/imports/queue.go --- a/pkg/imports/queue.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/imports/queue.go Thu Dec 20 15:33:29 2018 +0100 @@ -18,6 +18,7 @@ "database/sql" "encoding/json" "fmt" + "html/template" "log" "runtime/debug" "strings" @@ -28,6 +29,7 @@ "gemma.intevation.de/gemma/pkg/auth" "gemma.intevation.de/gemma/pkg/config" + "gemma.intevation.de/gemma/pkg/misc" ) type ( @@ -66,6 +68,8 @@ // JobCreator is used to bring a job to life as it is stored // in pure meta-data form to the database. JobCreator interface { + // Description is the long name of the import. + Description() string // Create build the actual job. // kind is the name of the import type. // data is a free form string to pass arguments to the creation @@ -519,6 +523,75 @@ } // TODO: Send email if sendEmail is set. log.Printf("import #%d finished: %s\n", idj.id, state) + if idj.sendEmail { + go sendNotificationMail(idj.user, jc.Description(), state, idj.id) + } }(jc, idj) } } + +const ( + selectEmailSQL = `SELECT email_address FROM users.list_users WHERE username = $1` + + importNotificationMailSubject = `import notification mail` +) + +var ( + importNotificationMailTmpl = template.Must( + template.New("notification").Parse(` +Dear {{ .User }}, + +a {{ .Description }} import on server {{ .Server }} triggered +this email notification. + +{{ if eq .State "accepted" }}The imported data were successfully integrated into the database.{{ end -}} +{{ if eq .State "failed" }}The import failed for some reasons.{{ end -}} +{{ if eq .State "pending" }}The imported data could be integrated into the database +but your final decision is needed.{{ end }} + +Please follow this link to have a closer look at the details: + +{{ .Server }}/#?review={{ .ID }} + +Best regards + Your service team`)) +) + +func sendNotificationMail(user, description, state string, id int64) { + config.WaitReady() + + ctx := context.Background() + var email string + if err := auth.RunAs(ctx, user, + func(conn *sql.Conn) error { + return conn.QueryRowContext(ctx, selectEmailSQL, user).Scan(&email) + }, + ); err != nil { + log.Printf("error: %v\n", err) + return + } + + data := struct { + User string + Description string + Server string + State string + ID int64 + }{ + User: user, + Description: description, + Server: config.ExternalURL(), + State: state, + ID: id, + } + + var body strings.Builder + if err := importNotificationMailTmpl.Execute(&body, &data); err != nil { + log.Printf("error: %v\n", err) + return + } + + if err := misc.SendMail(email, importNotificationMailSubject, body.String()); err != nil { + log.Printf("error: %v\n", err) + } +} diff -r 14bb1289b97b -r a0982c38eac0 pkg/imports/sr.go --- a/pkg/imports/sr.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/imports/sr.go Thu Dec 20 15:33:29 2018 +0100 @@ -73,6 +73,10 @@ RegisterJobCreator(SRJobKind, srJobCreator{}) } +func (srJobCreator) Description() string { + return "sounding results" +} + func (srJobCreator) Create(_ JobKind, data string) (Job, error) { sr := new(SoundingResult) if err := common.FromJSONString(data, sr); err != nil { diff -r 14bb1289b97b -r a0982c38eac0 pkg/models/bn.go --- a/pkg/models/bn.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/models/bn.go Thu Dec 20 15:33:29 2018 +0100 @@ -14,6 +14,7 @@ package models type BottleneckImport struct { - URL string `json:"url"` - Insecure bool `json:"insecure"` + URL string `json:"url"` + Insecure bool `json:"insecure"` + SendEmail bool `json:"send-email"` } diff -r 14bb1289b97b -r a0982c38eac0 pkg/models/gauge.go --- a/pkg/models/gauge.go Thu Dec 20 15:20:49 2018 +0100 +++ b/pkg/models/gauge.go Thu Dec 20 15:33:29 2018 +0100 @@ -22,8 +22,9 @@ // GaugeMeasurementImport contains data used to define the endpoint type GaugeMeasurementImport struct { - URL string `json:"url"` - Insecure bool `json:"insecure"` + URL string `json:"url"` + Insecure bool `json:"insecure"` + SendEmail bool `json:"send-email"` } // GaugeMeasurement holds information about a gauge and the latest measurement