diff --git a/checker.go b/checker.go index e5040bf3..3c5a2a8c 100644 --- a/checker.go +++ b/checker.go @@ -10,8 +10,6 @@ import ( func CheckServices() { services, _ = SelectAllServices() - core.Communications, _ = SelectAllCommunications() - LoadDefaultCommunications() for _, v := range services { obj := v go obj.StartCheckins() @@ -42,18 +40,24 @@ func (s *Service) Check() *Service { return s } defer response.Body.Close() + contents, _ := ioutil.ReadAll(response.Body) if s.Expected != "" { - contents, _ := ioutil.ReadAll(response.Body) match, _ := regexp.MatchString(s.Expected, string(contents)) if !match { + s.LastResponse = string(contents) + s.LastStatusCode = response.StatusCode s.Failure(fmt.Sprintf("HTTP Response Body did not match '%v'", s.Expected)) return s } } if s.ExpectedStatus != response.StatusCode { + s.LastResponse = string(contents) + s.LastStatusCode = response.StatusCode s.Failure(fmt.Sprintf("HTTP Status Code %v did not match %v", response.StatusCode, s.ExpectedStatus)) return s } + s.LastResponse = string(contents) + s.LastStatusCode = response.StatusCode s.Online = true s.Record(response) return s @@ -65,6 +69,7 @@ type HitData struct { func (s *Service) Record(response *http.Response) { s.Online = true + s.LastOnline = time.Now() data := HitData{ Latency: s.Latency, } @@ -82,5 +87,8 @@ func (s *Service) Failure(issue string) { Issue: issue, } s.CreateFailure(data) + + SendFailureEmail(s) + OnFailure(s) } diff --git a/comms/emailer.go b/comms/emailer.go deleted file mode 100644 index fd7aaa49..00000000 --- a/comms/emailer.go +++ /dev/null @@ -1,77 +0,0 @@ -package comms - -import ( - "bytes" - "crypto/tls" - "fmt" - "github.com/hunterlong/statup/types" - "gopkg.in/gomail.v2" - "html/template" - "log" - "time" -) - -var ( - Emailer *gomail.Dialer - Outgoing []*types.Email -) - -func AddEmail(email *types.Email) { - Outgoing = append(Outgoing, email) -} - -func EmailerQueue() { - defer EmailerQueue() - for _, out := range Outgoing { - fmt.Printf("sending email to: %v \n", out.To) - Send(out) - } - Outgoing = nil - fmt.Println("running emailer queue") - time.Sleep(10 * time.Second) -} - -func Send(em *types.Email) { - source := EmailTemplate("comms/templates/error.html", nil) - m := gomail.NewMessage() - m.SetHeader("From", "info@betatude.com") - m.SetHeader("To", em.To) - m.SetHeader("Subject", em.Subject) - m.SetBody("text/html", source) - if err := Emailer.DialAndSend(m); err != nil { - fmt.Println(err) - } -} - -func SendSample(em *types.Email) { - source := EmailTemplate("comms/templates/error.html", nil) - m := gomail.NewMessage() - m.SetHeader("From", "info@betatude.com") - m.SetHeader("To", em.To) - m.SetHeader("Subject", em.Subject) - m.SetBody("text/html", source) - if err := Emailer.DialAndSend(m); err != nil { - fmt.Println(err) - } -} - -func LoadMailer(config *types.Communication) *gomail.Dialer { - Emailer = gomail.NewDialer(config.Host, config.Port, config.Username, config.Password) - Emailer.TLSConfig = &tls.Config{InsecureSkipVerify: true} - return Emailer -} - -func EmailTemplate(tmpl string, data interface{}) string { - t := template.New("error.html") - var err error - t, err = t.ParseFiles(tmpl) - if err != nil { - panic(err) - } - var tpl bytes.Buffer - if err := t.Execute(&tpl, data); err != nil { - log.Println(err) - } - result := tpl.String() - return result -} diff --git a/communication.go b/communication.go index 942c842f..0817f311 100644 --- a/communication.go +++ b/communication.go @@ -1,15 +1,16 @@ package main import ( - "github.com/hunterlong/statup/comms" + "fmt" "github.com/hunterlong/statup/types" "time" ) func LoadDefaultCommunications() { emailer := SelectCommunication(1) - comms.LoadMailer(emailer) - go comms.EmailerQueue() + fmt.Println(emailer) + LoadMailer(emailer) + go EmailerQueue() } func LoadComms() { @@ -27,7 +28,7 @@ func Run(c *types.Communication) { Subject: "Test Email from Statup", } - comms.AddEmail(sample) + AddEmail(sample) } func SelectAllCommunications() ([]*types.Communication, error) { diff --git a/emailer.go b/emailer.go new file mode 100644 index 00000000..029065f5 --- /dev/null +++ b/emailer.go @@ -0,0 +1,101 @@ +package main + +import ( + "bytes" + "crypto/tls" + "fmt" + "github.com/hunterlong/statup/types" + "gopkg.in/gomail.v2" + "html/template" + "log" + "time" +) + +var ( + emailQue *Que +) + +type Que struct { + Mailer *gomail.Dialer + Outgoing []*types.Email + LastSent int + LastSentTime time.Time +} + +func AddEmail(email *types.Email) { + emailQue.Outgoing = append(emailQue.Outgoing, email) +} + +func EmailerQueue() { + defer EmailerQueue() + uniques := []*types.Email{} + for _, out := range emailQue.Outgoing { + if isUnique(uniques, out) { + fmt.Printf("sending email to: %v \n", out.To) + Send(out) + uniques = append(uniques, out) + } + } + emailQue.Outgoing = nil + fmt.Println("running emailer queue") + time.Sleep(60 * time.Second) +} + +func isUnique(arr []*types.Email, obj *types.Email) bool { + for _, v := range arr { + if v.To == obj.To && v.Subject == obj.Subject { + return false + } + } + return true +} + +func Send(em *types.Email) { + source := EmailTemplate(em.Template, em.Data) + m := gomail.NewMessage() + m.SetHeader("From", "info@betatude.com") + m.SetHeader("To", em.To) + m.SetHeader("Subject", em.Subject) + m.SetBody("text/html", source) + if err := emailQue.Mailer.DialAndSend(m); err != nil { + fmt.Println(err) + } + emailQue.LastSent++ + emailQue.LastSentTime = time.Now() +} + +func SendFailureEmail(service *Service) { + email := &types.Email{ + To: "info@socialeck.com", + Subject: fmt.Sprintf("Service %v is Failing", service.Name), + Template: "failure.html", + Data: service, + } + AddEmail(email) +} + +func LoadMailer(config *types.Communication) *gomail.Dialer { + emailQue = &Que{} + emailQue.Outgoing = []*types.Email{} + emailQue.Mailer = gomail.NewDialer(config.Host, config.Port, config.Username, config.Password) + emailQue.Mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true} + return emailQue.Mailer +} + +func EmailTemplate(tmpl string, data interface{}) string { + emailTpl, err := emailBox.String(tmpl) + if err != nil { + panic(err) + } + t := template.New("email") + t, err = t.Parse(emailTpl) + if err != nil { + panic(err) + } + var tpl bytes.Buffer + if err := t.Execute(&tpl, data); err != nil { + log.Println(err) + } + result := tpl.String() + return result +} diff --git a/exporter.go b/exporter.go index 9bebe904..069c1328 100644 --- a/exporter.go +++ b/exporter.go @@ -9,9 +9,16 @@ import ( var httpFunctions template.FuncMap -func init() { - - httpFunctions = template.FuncMap{ +func ExportIndexHTML() string { + out := index{*core, services} + nav, _ := tmplBox.String("nav.html") + footer, _ := tmplBox.String("footer.html") + render, err := tmplBox.String("index.html") + if err != nil { + panic(err) + } + t := template.New("message") + t.Funcs(template.FuncMap{ "js": func(html string) template.JS { return template.JS(html) }, @@ -24,20 +31,7 @@ func init() { "underscore": func(html string) string { return UnderScoreString(html) }, - } - -} - -func ExportIndexHTML() string { - out := index{*core, services} - nav, _ := tmplBox.String("nav.html") - footer, _ := tmplBox.String("footer.html") - render, err := tmplBox.String("index.html") - if err != nil { - panic(err) - } - t := template.New("message") - t.Funcs(httpFunctions) + }) t, _ = t.Parse(nav) t, _ = t.Parse(footer) t.Parse(render) diff --git a/comms/templates/error.html b/html/emails/error.html similarity index 100% rename from comms/templates/error.html rename to html/emails/error.html diff --git a/html/emails/failure.html b/html/emails/failure.html new file mode 100644 index 00000000..f3abd13e --- /dev/null +++ b/html/emails/failure.html @@ -0,0 +1,66 @@ + + + + + + Sample Email + + + + + + + + +
+ + + + + + +
+ + \ No newline at end of file diff --git a/html/tmpl/service.html b/html/tmpl/service.html index 0d78f8dc..10570ca5 100644 --- a/html/tmpl/service.html +++ b/html/tmpl/service.html @@ -163,6 +163,20 @@ + +
+

Last Response

+ + + +
+ +
+ +
+
+ +
{{end}} diff --git a/html/tmpl/setup.html b/html/tmpl/setup.html index 70a421ca..28b31474 100644 --- a/html/tmpl/setup.html +++ b/html/tmpl/setup.html @@ -74,6 +74,11 @@ +
+ + +
+
diff --git a/main.go b/main.go index 58c18b0d..5a846b42 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,7 @@ var ( cssBox *rice.Box jsBox *rice.Box tmplBox *rice.Box + emailBox *rice.Box setupMode bool allPlugins []plugin.PluginActions ) @@ -152,6 +153,8 @@ func mainProcess() { RunHTTPServer() } CheckServices() + core.Communications, _ = SelectAllCommunications() + LoadDefaultCommunications() if !setupMode { LoadPlugins() RunHTTPServer() @@ -221,6 +224,7 @@ func RenderBoxes() { cssBox = rice.MustFindBox("html/css") jsBox = rice.MustFindBox("html/js") tmplBox = rice.MustFindBox("html/tmpl") + emailBox = rice.MustFindBox("html/emails") } func LoadConfig() (*Config, error) { diff --git a/services.go b/services.go index 3d5ecb77..04e05134 100644 --- a/services.go +++ b/services.go @@ -35,6 +35,9 @@ type Service struct { Failures []*Failure `json:"failures"` Checkins []*Checkin `json:"checkins"` runRoutine bool + LastResponse string + LastStatusCode int + LastOnline time.Time } func serviceCol() db.Collection { diff --git a/setup.go b/setup.go index 05ae241b..0b7e5752 100644 --- a/setup.go +++ b/setup.go @@ -45,6 +45,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) { sample := r.PostForm.Get("sample_data") description := r.PostForm.Get("description") domain := r.PostForm.Get("domain") + email := r.PostForm.Get("email") config := &DbConfig{ dbConn, @@ -85,6 +86,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) { admin := &User{ Username: config.Username, Password: config.Password, + Email: email, Admin: true, } admin.Create() diff --git a/types/types.go b/types/types.go index c6483ab2..a1085574 100644 --- a/types/types.go +++ b/types/types.go @@ -24,5 +24,4 @@ type Email struct { Subject string Template string Data interface{} - Body string } diff --git a/users.go b/users.go index 30681868..a57ccee3 100644 --- a/users.go +++ b/users.go @@ -2,6 +2,7 @@ package main import ( "golang.org/x/crypto/bcrypt" + "net/http" "time" ) @@ -16,6 +17,19 @@ type User struct { CreatedAt time.Time `db:"created_at" json:"created_at"` } +func SessionUser(r *http.Request) *User { + session, _ := store.Get(r, cookieKey) + if session == nil { + return nil + } + uuid := session.Values["user_id"] + var user *User + col := dbSession.Collection("users") + res := col.Find("id", uuid) + res.One(&user) + return user +} + func SelectUser(id int64) (*User, error) { var user User col := dbSession.Collection("users") @@ -40,8 +54,7 @@ func (u *User) Delete() error { func (u *User) Create() (int64, error) { u.CreatedAt = time.Now() - password := HashPassword(u.Password) - u.Password = password + u.Password = HashPassword(u.Password) u.ApiKey = NewSHA1Hash(5) u.ApiSecret = NewSHA1Hash(10) col := dbSession.Collection("users") diff --git a/web.go b/web.go index 7a0bec13..13e2c0a6 100644 --- a/web.go +++ b/web.go @@ -5,7 +5,6 @@ import ( "github.com/fatih/structs" "github.com/gorilla/mux" "github.com/gorilla/sessions" - "github.com/hunterlong/statup/comms" "github.com/hunterlong/statup/types" "html/template" "net/http" @@ -96,9 +95,10 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { r.ParseForm() username := r.PostForm.Get("username") password := r.PostForm.Get("password") - _, auth := AuthUser(username, password) + user, auth := AuthUser(username, password) if auth { session.Values["authenticated"] = true + session.Values["user_id"] = user.Id session.Save(r, w) http.Redirect(w, r, "/dashboard", http.StatusSeeOther) } else { @@ -265,13 +265,11 @@ func SaveEmailSettingsHandler(w http.ResponseWriter, r *http.Request) { Update(emailer) sample := &types.Email{ - To: "info@socialeck.com", + To: SessionUser(r).Email, Subject: "Sample Email", - Template: "templates/error.html", - Body: "okkokkok", + Template: "error.html", } - - comms.AddEmail(sample) + AddEmail(sample) http.Redirect(w, r, "/settings", http.StatusSeeOther) } @@ -416,11 +414,6 @@ func ServicesBadgeHandler(w http.ResponseWriter, r *http.Request) { } func ServicesViewHandler(w http.ResponseWriter, r *http.Request) { - auth := IsAuthenticated(r) - if !auth { - http.Redirect(w, r, "/", http.StatusSeeOther) - return - } vars := mux.Vars(r) service := SelectService(StringInt(vars["id"])) ExecuteResponse(w, r, "service.html", service) @@ -450,6 +443,9 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i "underscore": func(html string) string { return UnderScoreString(html) }, + "User": func() *User { + return SessionUser(r) + }, }) t, _ = t.Parse(nav) t, _ = t.Parse(footer)