pull/10/head
hunterlong 2018-06-22 17:10:37 -07:00
parent dbb73f7651
commit 8d8f25ea23
18 changed files with 300 additions and 58 deletions

4
api.go
View File

@ -20,13 +20,13 @@ func ApiCheckinHandler(w http.ResponseWriter, r *http.Request) {
func ApiServiceHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
service, _ := SelectService(StringInt(vars["id"]))
service := SelectService(StringInt(vars["id"]))
json.NewEncoder(w).Encode(service)
}
func ApiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
service, _ := SelectService(StringInt(vars["id"]))
service := SelectService(StringInt(vars["id"]))
var s Service
decoder := json.NewDecoder(r.Body)

53
comms/emailer.go Normal file
View File

@ -0,0 +1,53 @@
package comms
import (
"bytes"
"crypto/tls"
"fmt"
"gopkg.in/gomail.v2"
"html/template"
"log"
"os"
)
var (
mailer *gomail.Dialer
)
func NewMailer() {
mailer = gomail.NewDialer(os.Getenv("HOST"), 587, os.Getenv("USER"), os.Getenv("PASS"))
mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
source := EmailTemplate("comms/templates/error.html", "this is coooool")
fmt.Println("source: ", source)
}
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
}
func SendEmail(to, subject, body string) {
m := gomail.NewMessage()
m.SetHeader("From", "info@email.com")
m.SetHeader("To", to)
m.SetHeader("Subject", subject)
m.SetBody("text/html", body)
if err := mailer.DialAndSend(m); err != nil {
fmt.Println(err)
}
}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
</head>
<body>
<p>
<strong>Hello {{.}}</strong>
</p>
</body>
</html>

80
communication.go Normal file
View File

@ -0,0 +1,80 @@
package main
import "time"
var (
Communications []*Communication
)
type Communication struct {
Id int64 `db:"id,omitempty" json:"id"`
Method string `db:"method" json:"method"`
Host string `db:"host" json:"host"`
Port int64 `db:"port" json:"port"`
User string `db:"user" json:"user"`
Password string `db:"password" json:"-"`
Var1 string `db:"var1" json:"var1"`
Var2 string `db:"var2" json:"var2"`
ApiKey string `db:"api_key" json:"api_key"`
ApiSecret string `db:"api_secret" json:"api_secret"`
Enabled bool `db:"enabled" json:"enabled"`
Limits int64 `db:"limits" json:"limits"`
Removable bool `db:"removable" json:"removable"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
}
func OnCommunicate() {
for _, c := range Communications {
if c.Enabled {
c.Run()
}
}
}
func (c *Communication) Run() {
}
func SelectAllCommunications() ([]*Communication, error) {
var c []*Communication
col := dbSession.Collection("communication").Find()
err := col.All(&c)
Communications = c
return c, err
}
func (c *Communication) Create() (int64, error) {
c.CreatedAt = time.Now()
uuid, err := dbSession.Collection("communication").Insert(c)
if uuid == nil {
return 0, err
}
c.Id = uuid.(int64)
Communications = append(Communications, c)
return uuid.(int64), err
}
func (c *Communication) Disable() {
c.Enabled = false
c.Update()
}
func (c *Communication) Enable() {
c.Enabled = true
c.Update()
}
func (c *Communication) Update() *Communication {
col := dbSession.Collection("communication").Find("id", c.Id)
col.Update(c)
return c
}
func SelectCommunication(id int64) *Communication {
for _, c := range Communications {
if c.Id == id {
return c
}
}
return nil
}

View File

@ -13,6 +13,7 @@ type Core struct {
ApiSecret string `db:"api_secret"`
Style string `db:"style"`
Footer string `db:"footer"`
Domain string `db:"domain"`
Version string `db:"version"`
Plugins []plugin.Info
Repos []PluginJSON

View File

@ -27,11 +27,11 @@ func (s *Service) CreateFailure(data FailureData) (int64, error) {
return uuid.(int64), err
}
func (s *Service) SelectAllFailures() ([]*Failure, error) {
func (s *Service) SelectAllFailures() []*Failure {
var fails []*Failure
col := dbSession.Collection("failures").Find("service", s.Id).OrderBy("-id")
err := col.All(&fails)
return fails, err
col.All(&fails)
return fails
}
func (u *Service) DeleteFailures() {

View File

@ -116,8 +116,8 @@
</div>
</div>
<div class="form-group row">
<label for="service_url" class="col-sm-12 col-form-label">Application Endpoint (URL)</label>
<div class="col-12">
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
<div class="col-sm-8">
<input type="text" name="domain" class="form-control" id="service_url" value="{{.Domain}}" placeholder="https://google.com">
</div>
</div>
@ -194,20 +194,10 @@
label: 'Response Time (Milliseconds)',
data: {{js .GraphData}},
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
'rgba(47, 206, 30, 0.92)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
'rgb(47, 171, 34)'
],
borderWidth: 1
}]

View File

@ -64,8 +64,8 @@
</div>
</div>
<div class="form-group row">
<label for="service_url" class="col-sm-12 col-form-label">Application Endpoint (URL)</label>
<div class="col-12">
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
<div class="col-sm-8">
<input type="text" name="domain" class="form-control" id="service_url" placeholder="https://google.com">
</div>
</div>

View File

@ -6,6 +6,7 @@ import (
"github.com/GeertJohan/go.rice"
"github.com/go-yaml/yaml"
"github.com/gorilla/sessions"
"github.com/hunterlong/statup/comms"
"github.com/hunterlong/statup/plugin"
"golang.org/x/crypto/bcrypt"
"io"
@ -124,6 +125,9 @@ func DownloadFile(filepath string, url string) error {
func main() {
var err error
fmt.Printf("Starting Statup v%v\n", VERSION)
comms.NewMailer()
RenderBoxes()
configs, err = LoadConfig()
if err != nil {

View File

@ -140,8 +140,8 @@ func TestUser_Create(t *testing.T) {
}
func TestOneService_Check(t *testing.T) {
service, err := SelectService(1)
assert.Nil(t, err)
service := SelectService(1)
assert.NotNil(t, service)
assert.Equal(t, "Google", service.Name)
}
@ -161,32 +161,30 @@ func TestService_Create(t *testing.T) {
}
func TestService_Check(t *testing.T) {
service, err := SelectService(2)
assert.Nil(t, err)
service := SelectService(2)
assert.NotNil(t, service)
assert.Equal(t, "Statup.io", service.Name)
out := service.Check()
assert.Equal(t, true, out.Online)
}
func TestService_AvgTime(t *testing.T) {
service, err := SelectService(1)
assert.Nil(t, err)
service := SelectService(1)
assert.NotNil(t, service)
avg := service.AvgUptime()
assert.Nil(t, err)
assert.Equal(t, "100", avg)
}
func TestService_Online24(t *testing.T) {
service, err := SelectService(1)
assert.Nil(t, err)
service := SelectService(1)
assert.NotNil(t, service)
online := service.Online24()
assert.Nil(t, err)
assert.Equal(t, float32(100), online)
}
func TestService_GraphData(t *testing.T) {
service, err := SelectService(1)
assert.Nil(t, err)
service := SelectService(1)
assert.NotNil(t, service)
data := service.GraphData()
assert.NotEmpty(t, data)
}
@ -207,22 +205,22 @@ func TestBadService_Create(t *testing.T) {
}
func TestBadService_Check(t *testing.T) {
service, err := SelectService(4)
assert.Nil(t, err)
service := SelectService(4)
assert.NotNil(t, service)
assert.Equal(t, "Github Failing Check", service.Name)
}
func TestService_Hits(t *testing.T) {
service, err := SelectService(1)
assert.Nil(t, err)
service := SelectService(1)
assert.NotNil(t, service)
hits, err := service.Hits()
assert.Nil(t, err)
assert.Equal(t, 20, len(hits))
}
func TestService_LimitedHits(t *testing.T) {
service, err := SelectService(1)
assert.Nil(t, err)
service := SelectService(1)
assert.NotNil(t, service)
hits, err := service.LimitedHits()
assert.Nil(t, err)
assert.Equal(t, 20, len(hits))

View File

@ -23,6 +23,7 @@ type Service struct {
Interval int `db:"check_interval" json:"check_interval"`
Type string `db:"check_type" json:"type"`
Method string `db:"method" json:"method"`
PostData string `db:"post_data" json:"post_data"`
Port int `db:"port" json:"port"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
Online bool `json:"online"`
@ -30,30 +31,34 @@ type Service struct {
Online24Hours float32 `json:"24_hours_online"`
AvgResponse string `json:"avg_response"`
TotalUptime string `json:"uptime"`
OrderId int64 `json:"order_id"`
Failures []*Failure `json:"failures"`
Checkins []*Checkin `json:"checkins"`
runRoutine bool
}
func serviceCol() db.Collection {
return dbSession.Collection("services")
}
func SelectService(id int64) (*Service, error) {
var service *Service
res := serviceCol().Find("id", id)
err := res.One(&service)
service.Checkins = service.SelectAllCheckins()
return service, err
func SelectService(id int64) *Service {
for _, s := range services {
if s.Id == id {
return s
}
}
return nil
}
func SelectAllServices() ([]*Service, error) {
var services []*Service
var srvcs []*Service
col := serviceCol().Find()
err := col.All(&services)
for _, s := range services {
err := col.All(&srvcs)
for _, s := range srvcs {
s.Checkins = s.SelectAllCheckins()
s.Failures = s.SelectAllFailures()
}
return services, err
return srvcs, err
}
func (s *Service) AvgTime() float64 {
@ -132,9 +137,21 @@ func (s *Service) AvgUptime() string {
return s.TotalUptime
}
func (u *Service) RemoveArray() []*Service {
var srvcs []*Service
for _, s := range services {
if s.Id != u.Id {
srvcs = append(srvcs, s)
}
}
services = srvcs
return srvcs
}
func (u *Service) Delete() error {
res := serviceCol().Find("id", u.Id)
err := res.Delete()
u.RemoveArray()
OnDeletedService(u)
return err
}
@ -151,6 +168,7 @@ func (u *Service) Create() (int64, error) {
}
u.Id = uuid.(int64)
services = append(services, u)
go u.CheckQueue()
OnNewService(u)
return uuid.(int64), err
}

View File

@ -26,6 +26,10 @@ type DbConfig struct {
}
func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
if core.ApiKey != "" {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
r.ParseForm()
dbHost := r.PostForm.Get("db_host")
dbUser := r.PostForm.Get("db_user")
@ -77,9 +81,12 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
admin := &User{
Username: config.Username,
Password: config.Password,
Admin: true,
}
admin.Create()
InsertDefaultComms()
if sample == "on" {
go LoadSampleData()
}
@ -89,6 +96,15 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
mainProcess()
}
func InsertDefaultComms() {
emailer := &Communication{
Method: "email",
Removable: false,
Enabled: false,
}
emailer.Create()
}
func DeleteConfig() {
err := os.Remove("./config.yml")
if err != nil {
@ -145,6 +161,7 @@ func (c *DbConfig) Save() error {
NewSHA1Hash(10),
"",
"",
"",
VERSION,
[]plugin.Info{},
[]PluginJSON{},

View File

@ -3,4 +3,5 @@ DROP table hits;
DROP table failures;
DROP table users;
DROP table checkins;
DROP table services;
DROP table services;
DROP table communication;

View File

@ -6,6 +6,7 @@ CREATE TABLE core (
api_secret VARCHAR(50),
style text,
footer text,
domain text,
version VARCHAR(50)
);
CREATE TABLE users (
@ -15,6 +16,7 @@ CREATE TABLE users (
email text,
api_key VARCHAR(50),
api_secret VARCHAR(50),
admin bool,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (id)
);
@ -28,6 +30,8 @@ CREATE TABLE services (
expected text,
expected_status INT(6),
check_interval int(11),
post_data text,
order_id integer,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (id)
);
@ -55,4 +59,20 @@ CREATE TABLE checkins (
created_at TIMESTAMP,
INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id)
);
CREATE TABLE communication (
id SERIAL PRIMARY KEY,
method text,
host text,
port integer,
user text,
password text,
var1 text,
var2 text,
api_key text,
api_secret text,
enabled boolean,
removable boolean,
limits integer,
created_at TIMESTAMP
);

View File

@ -6,6 +6,7 @@ CREATE TABLE core (
api_secret text,
style text,
footer text,
domain text,
version text
);
@ -16,6 +17,7 @@ CREATE TABLE users (
email text,
api_key text,
api_secret text,
admin bool,
created_at TIMESTAMP
);
@ -29,6 +31,8 @@ CREATE TABLE services (
expected text,
expected_status integer,
check_interval integer,
post_data text,
order_id integer,
created_at TIMESTAMP
);
@ -55,6 +59,23 @@ CREATE TABLE checkins (
created_at TIMESTAMP
);
CREATE TABLE communication (
id SERIAL PRIMARY KEY,
method text,
host text,
port integer,
user text,
password text,
var1 text,
var2 text,
api_key text,
api_secret text,
enabled boolean,
removable boolean,
limits integer,
created_at TIMESTAMP
);
CREATE INDEX idx_hits ON hits(service);
CREATE INDEX idx_failures ON failures(service);

View File

@ -6,6 +6,7 @@ CREATE TABLE core (
api_secret text,
style text,
footer text,
domain text,
version text
);
@ -16,6 +17,7 @@ CREATE TABLE users (
email text,
api_key text,
api_secret text,
admin bool,
created_at TIMESTAMP
);
@ -29,6 +31,8 @@ CREATE TABLE services (
expected text,
expected_status integer,
check_interval integer,
post_data text,
order_id integer,
created_at TIMESTAMP
);
@ -54,6 +58,24 @@ CREATE TABLE checkins (
created_at TIMESTAMP
);
CREATE TABLE communication (
id SERIAL PRIMARY KEY,
method text,
host text,
port integer,
user text,
password text,
var1 text,
var2 text,
api_key text,
api_secret text,
enabled boolean,
removable boolean,
limits integer,
created_at TIMESTAMP
);
CREATE INDEX idx_hits ON hits(service);
CREATE INDEX idx_failures ON failures(service);
CREATE INDEX idx_checkins ON checkins(service);

View File

@ -12,6 +12,7 @@ type User struct {
Email string `db:"email" json:"-"`
ApiKey string `db:"api_key" json:"api_key"`
ApiSecret string `db:"api_secret" json:"-"`
Admin bool `db:"admin" json:"admin"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
}

17
web.go
View File

@ -48,7 +48,6 @@ func Router() *mux.Router {
r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler))
r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST")
r.Handle("/help", http.HandlerFunc(HelpHandler))
r.Handle("/api", http.HandlerFunc(ApiIndexHandler))
r.Handle("/api/checkin/{api}", http.HandlerFunc(ApiCheckinHandler))
r.Handle("/api/services", http.HandlerFunc(ApiAllServicesHandler))
@ -151,6 +150,10 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
}
func SetupHandler(w http.ResponseWriter, r *http.Request) {
if core.ApiKey != "" {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
ExecuteResponse(w, r, "setup.html", nil)
}
@ -209,10 +212,8 @@ func ServicesDeleteHandler(w http.ResponseWriter, r *http.Request) {
return
}
vars := mux.Vars(r)
service, _ := SelectService(StringInt(vars["id"]))
service := SelectService(StringInt(vars["id"]))
service.Delete()
services, _ = SelectAllServices()
http.Redirect(w, r, "/services", http.StatusSeeOther)
}
@ -223,7 +224,7 @@ func ServicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
return
}
vars := mux.Vars(r)
service, _ := SelectService(StringInt(vars["id"]))
service := SelectService(StringInt(vars["id"]))
service.DeleteFailures()
services, _ = SelectAllServices()
@ -345,7 +346,7 @@ func CheckinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
}
vars := mux.Vars(r)
interval := StringInt(r.PostForm.Get("interval"))
service, _ := SelectService(StringInt(vars["id"]))
service := SelectService(StringInt(vars["id"]))
checkin := &Checkin{
Service: service.Id,
Interval: interval,
@ -365,7 +366,7 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
func ServicesBadgeHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
service, _ := SelectService(StringInt(vars["id"]))
service := SelectService(StringInt(vars["id"]))
var badge []byte
if service.Online {
@ -388,7 +389,7 @@ func ServicesViewHandler(w http.ResponseWriter, r *http.Request) {
return
}
vars := mux.Vars(r)
service, _ := SelectService(StringInt(vars["id"]))
service := SelectService(StringInt(vars["id"]))
ExecuteResponse(w, r, "service.html", service)
}