mirror of https://github.com/statping/statping
upgrades
parent
8d8f25ea23
commit
68b42dcb8b
|
@ -10,6 +10,8 @@ import (
|
||||||
|
|
||||||
func CheckServices() {
|
func CheckServices() {
|
||||||
services, _ = SelectAllServices()
|
services, _ = SelectAllServices()
|
||||||
|
core.Communications, _ = SelectAllCommunications()
|
||||||
|
LoadDefaultCommunications()
|
||||||
for _, v := range services {
|
for _, v := range services {
|
||||||
obj := v
|
obj := v
|
||||||
go obj.StartCheckins()
|
go obj.StartCheckins()
|
||||||
|
|
|
@ -4,50 +4,74 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/hunterlong/statup/types"
|
||||||
"gopkg.in/gomail.v2"
|
"gopkg.in/gomail.v2"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mailer *gomail.Dialer
|
Emailer *gomail.Dialer
|
||||||
|
Outgoing []*types.Email
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewMailer() {
|
func AddEmail(email *types.Email) {
|
||||||
mailer = gomail.NewDialer(os.Getenv("HOST"), 587, os.Getenv("USER"), os.Getenv("PASS"))
|
Outgoing = append(Outgoing, email)
|
||||||
mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
}
|
||||||
|
|
||||||
source := EmailTemplate("comms/templates/error.html", "this is coooool")
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("source: ", source)
|
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 {
|
func EmailTemplate(tmpl string, data interface{}) string {
|
||||||
t := template.New("error.html")
|
t := template.New("error.html")
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
t, err = t.ParseFiles(tmpl)
|
t, err = t.ParseFiles(tmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tpl bytes.Buffer
|
var tpl bytes.Buffer
|
||||||
if err := t.Execute(&tpl, data); err != nil {
|
if err := t.Execute(&tpl, data); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
result := tpl.String()
|
result := tpl.String()
|
||||||
return result
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1,61 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<html>
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>Sample Email</title>
|
||||||
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
<body style="-webkit-text-size-adjust: none; box-sizing: border-box; color: #74787E; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; height: 100%; line-height: 1.4; margin: 0; width: 100% !important;" bgcolor="#F2F4F6"><style type="text/css">
|
||||||
|
body {
|
||||||
|
width: 100% !important; height: 100%; margin: 0; line-height: 1.4; background-color: #F2F4F6; color: #74787E; -webkit-text-size-adjust: none;
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.email-body_inner {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.email-footer {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 500px) {
|
||||||
|
.button {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin: 0; padding: 0; width: 100%;" bgcolor="#F2F4F6">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; word-break: break-word;">
|
||||||
|
<table class="email-content" width="100%" cellpadding="0" cellspacing="0" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin: 0; padding: 0; width: 100%;">
|
||||||
|
|
||||||
<body>
|
<tr>
|
||||||
<p>
|
<td class="email-body" width="100%" cellpadding="0" cellspacing="0" style="-premailer-cellpadding: 0; -premailer-cellspacing: 0; border-bottom-color: #EDEFF2; border-bottom-style: solid; border-bottom-width: 1px; border-top-color: #EDEFF2; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin: 0; padding: 0; width: 100%; word-break: break-word;" bgcolor="#FFFFFF">
|
||||||
<strong>Hello {{.}}</strong>
|
<table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin: 0 auto; padding: 0; width: 570px;" bgcolor="#FFFFFF">
|
||||||
|
|
||||||
</p>
|
<tr>
|
||||||
|
<td class="content-cell" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; padding: 35px; word-break: break-word;">
|
||||||
|
<h1 style="box-sizing: border-box; color: #2F3133; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 19px; font-weight: bold; margin-top: 0;" align="left">Looks like emails work!</h1>
|
||||||
|
<p style="box-sizing: border-box; color: #74787E; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 16px; line-height: 1.5em; margin-top: 0;" align="left">
|
||||||
|
Since you got this email, it confirms that your Statup Status Page email system is working correctly.
|
||||||
|
</p>
|
||||||
|
</p>
|
||||||
|
<p style="box-sizing: border-box; color: #74787E; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 16px; line-height: 1.5em; margin-top: 0;" align="left">
|
||||||
|
Enjoy using Statup!
|
||||||
|
<br />Statup.io Team</p>
|
||||||
|
|
||||||
|
<table class="body-sub" style="border-top-color: #EDEFF2; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin-top: 25px; padding-top: 25px;">
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,77 +1,75 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"github.com/hunterlong/statup/comms"
|
||||||
var (
|
"github.com/hunterlong/statup/types"
|
||||||
Communications []*Communication
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Communication struct {
|
func LoadDefaultCommunications() {
|
||||||
Id int64 `db:"id,omitempty" json:"id"`
|
emailer := SelectCommunication(1)
|
||||||
Method string `db:"method" json:"method"`
|
comms.LoadMailer(emailer)
|
||||||
Host string `db:"host" json:"host"`
|
go comms.EmailerQueue()
|
||||||
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() {
|
func LoadComms() {
|
||||||
for _, c := range Communications {
|
for _, c := range core.Communications {
|
||||||
if c.Enabled {
|
if c.Enabled {
|
||||||
c.Run()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communication) Run() {
|
func Run(c *types.Communication) {
|
||||||
|
|
||||||
|
sample := &types.Email{
|
||||||
|
To: "info@socialeck.com",
|
||||||
|
Subject: "Test Email from Statup",
|
||||||
|
}
|
||||||
|
|
||||||
|
comms.AddEmail(sample)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SelectAllCommunications() ([]*Communication, error) {
|
func SelectAllCommunications() ([]*types.Communication, error) {
|
||||||
var c []*Communication
|
var c []*types.Communication
|
||||||
col := dbSession.Collection("communication").Find()
|
col := dbSession.Collection("communication").Find()
|
||||||
err := col.All(&c)
|
err := col.All(&c)
|
||||||
Communications = c
|
core.Communications = c
|
||||||
return c, err
|
return c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communication) Create() (int64, error) {
|
func Create(c *types.Communication) (int64, error) {
|
||||||
c.CreatedAt = time.Now()
|
c.CreatedAt = time.Now()
|
||||||
uuid, err := dbSession.Collection("communication").Insert(c)
|
uuid, err := dbSession.Collection("communication").Insert(c)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
if uuid == nil {
|
if uuid == nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
c.Id = uuid.(int64)
|
c.Id = uuid.(int64)
|
||||||
Communications = append(Communications, c)
|
core.Communications = append(core.Communications, c)
|
||||||
return uuid.(int64), err
|
return uuid.(int64), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communication) Disable() {
|
func Disable(c *types.Communication) {
|
||||||
c.Enabled = false
|
c.Enabled = false
|
||||||
c.Update()
|
Update(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communication) Enable() {
|
func Enable(c *types.Communication) {
|
||||||
c.Enabled = true
|
c.Enabled = true
|
||||||
c.Update()
|
Update(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communication) Update() *Communication {
|
func Update(c *types.Communication) *types.Communication {
|
||||||
col := dbSession.Collection("communication").Find("id", c.Id)
|
col := dbSession.Collection("communication").Find("id", c.Id)
|
||||||
col.Update(c)
|
col.Update(c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func SelectCommunication(id int64) *Communication {
|
func SelectCommunication(id int64) *types.Communication {
|
||||||
for _, c := range Communications {
|
for _, c := range core.Communications {
|
||||||
if c.Id == id {
|
if c.Id == id {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
26
core.go
26
core.go
|
@ -3,21 +3,23 @@ package main
|
||||||
import (
|
import (
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/hunterlong/statup/plugin"
|
"github.com/hunterlong/statup/plugin"
|
||||||
|
"github.com/hunterlong/statup/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Core struct {
|
type Core struct {
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
Description string `db:"description"`
|
Description string `db:"description"`
|
||||||
Config string `db:"config"`
|
Config string `db:"config"`
|
||||||
ApiKey string `db:"api_key"`
|
ApiKey string `db:"api_key"`
|
||||||
ApiSecret string `db:"api_secret"`
|
ApiSecret string `db:"api_secret"`
|
||||||
Style string `db:"style"`
|
Style string `db:"style"`
|
||||||
Footer string `db:"footer"`
|
Footer string `db:"footer"`
|
||||||
Domain string `db:"domain"`
|
Domain string `db:"domain"`
|
||||||
Version string `db:"version"`
|
Version string `db:"version"`
|
||||||
Plugins []plugin.Info
|
Plugins []plugin.Info
|
||||||
Repos []PluginJSON
|
Repos []PluginJSON
|
||||||
PluginFields []PluginSelect
|
PluginFields []PluginSelect
|
||||||
|
Communications []*types.Communication
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) Update() (*Core, error) {
|
func (c *Core) Update() (*Core, error) {
|
||||||
|
|
|
@ -61,3 +61,7 @@ func DbConnection(dbType string) error {
|
||||||
OnLoad(dbSession)
|
OnLoad(dbSession)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Backup() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
type Failure struct {
|
type Failure struct {
|
||||||
Id int `db:"id,omitempty"`
|
Id int `db:"id,omitempty"`
|
||||||
Issue string `db:"issue"`
|
Issue string `db:"issue"`
|
||||||
|
Method string `db:"method"`
|
||||||
Service int64 `db:"service"`
|
Service int64 `db:"service"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,10 @@
|
||||||
|
|
||||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||||
<a class="nav-link active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">Settings</a>
|
<a class="nav-link active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">Settings</a>
|
||||||
<a class="nav-link" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-style" role="tab" aria-controls="v-pills-style" aria-selected="false">Styling</a>
|
<a class="nav-link" id="v-pills-style-tab" data-toggle="pill" href="#v-pills-style" role="tab" aria-controls="v-pills-style" aria-selected="false">Styling</a>
|
||||||
|
{{ range .Communications }}
|
||||||
|
<a class="nav-link text-uppercase" id="v-pills-{{ .Method }}-tab" data-toggle="pill" href="#v-pills-{{ .Method }}" role="tab" aria-controls="v-pills-{{ .Method }}" aria-selected="false">{{ .Method }}</a>
|
||||||
|
{{ end }}
|
||||||
<a class="nav-link" id="v-pills-browse-tab" data-toggle="pill" href="#v-pills-browse" role="tab" aria-controls="v-pills-home" aria-selected="false">Browse Plugins</a>
|
<a class="nav-link" id="v-pills-browse-tab" data-toggle="pill" href="#v-pills-browse" role="tab" aria-controls="v-pills-home" aria-selected="false">Browse Plugins</a>
|
||||||
{{ range .Plugins }}
|
{{ range .Plugins }}
|
||||||
<a class="nav-link text-capitalize" id="v-pills-{{underscore .Name}}-tab" data-toggle="pill" href="#v-pills-{{underscore .Name}}" role="tab" aria-controls="v-pills-profile" aria-selected="false">{{.Name}}</a>
|
<a class="nav-link text-capitalize" id="v-pills-{{underscore .Name}}-tab" data-toggle="pill" href="#v-pills-{{underscore .Name}}" role="tab" aria-controls="v-pills-profile" aria-selected="false">{{.Name}}</a>
|
||||||
|
@ -72,6 +75,48 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{ range .Communications }}
|
||||||
|
<div class="tab-pane fade" id="v-pills-{{ .Method }}" role="tabpanel" aria-labelledby="v-pills-{{ .Method }}-tab">
|
||||||
|
|
||||||
|
<form method="POST" action="/settings/{{ .Method }}">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="formGroupExampleInput">SMTP Host</label>
|
||||||
|
<input type="text" name="host" class="form-control" value="{{ .Host }}" id="formGroupExampleInput" placeholder="Great Uptime">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="formGroupExampleInput">SMTP Username</label>
|
||||||
|
<input type="text" name="username" class="form-control" value="{{ .Username }}" id="formGroupExampleInput" placeholder="Great Uptime">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="formGroupExampleInput">SMTP Password</label>
|
||||||
|
<input type="password" name="password" class="form-control" value="{{ .Password }}" id="formGroupExampleInput">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="formGroupExampleInput">SMTP Port</label>
|
||||||
|
<input type="number" name="port" class="form-control" value="{{ .Port }}" id="formGroupExampleInput" placeholder="587">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="formGroupExampleInput">Outgoing Email Address</label>
|
||||||
|
<input type="text" name="address" class="form-control" value="{{ .Var1 }}" id="formGroupExampleInput" placeholder="noreply@domain.com">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="formGroupExampleInput">Limit Emails per Hour</label>
|
||||||
|
<input type="number" name="limit" class="form-control" value="30" id="formGroupExampleInput" placeholder="noreply@domain.com">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">Save Email Settings</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
<div class="tab-pane fade" id="v-pills-browse" role="tabpanel" aria-labelledby="v-pills-browse-tab">
|
<div class="tab-pane fade" id="v-pills-browse" role="tabpanel" aria-labelledby="v-pills-browse-tab">
|
||||||
{{ range .Repos }}
|
{{ range .Repos }}
|
||||||
<div class="card col-6" style="width: 18rem;">
|
<div class="card col-6" style="width: 18rem;">
|
||||||
|
|
3
main.go
3
main.go
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/GeertJohan/go.rice"
|
"github.com/GeertJohan/go.rice"
|
||||||
"github.com/go-yaml/yaml"
|
"github.com/go-yaml/yaml"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/hunterlong/statup/comms"
|
|
||||||
"github.com/hunterlong/statup/plugin"
|
"github.com/hunterlong/statup/plugin"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -126,8 +125,6 @@ func main() {
|
||||||
var err error
|
var err error
|
||||||
fmt.Printf("Starting Statup v%v\n", VERSION)
|
fmt.Printf("Starting Statup v%v\n", VERSION)
|
||||||
|
|
||||||
comms.NewMailer()
|
|
||||||
|
|
||||||
RenderBoxes()
|
RenderBoxes()
|
||||||
configs, err = LoadConfig()
|
configs, err = LoadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
15
main_test.go
15
main_test.go
|
@ -23,6 +23,7 @@ func TestMySQLMakeConfig(t *testing.T) {
|
||||||
3306,
|
3306,
|
||||||
"Testing MYSQL",
|
"Testing MYSQL",
|
||||||
"This is a test of Statup.io!",
|
"This is a test of Statup.io!",
|
||||||
|
"",
|
||||||
"admin",
|
"admin",
|
||||||
"admin",
|
"admin",
|
||||||
nil,
|
nil,
|
||||||
|
@ -36,7 +37,7 @@ func TestMySQLMakeConfig(t *testing.T) {
|
||||||
|
|
||||||
err = DbConnection(configs.Connection)
|
err = DbConnection(configs.Connection)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
InsertDefaultComms()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertMysqlSample(t *testing.T) {
|
func TestInsertMysqlSample(t *testing.T) {
|
||||||
|
@ -62,6 +63,7 @@ func TestSqliteMakeConfig(t *testing.T) {
|
||||||
5432,
|
5432,
|
||||||
"Testing SQLITE",
|
"Testing SQLITE",
|
||||||
"This is a test of Statup.io!",
|
"This is a test of Statup.io!",
|
||||||
|
"",
|
||||||
"admin",
|
"admin",
|
||||||
"admin",
|
"admin",
|
||||||
nil,
|
nil,
|
||||||
|
@ -75,6 +77,7 @@ func TestSqliteMakeConfig(t *testing.T) {
|
||||||
|
|
||||||
err = DbConnection(configs.Connection)
|
err = DbConnection(configs.Connection)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
InsertDefaultComms()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertSqliteSample(t *testing.T) {
|
func TestInsertSqliteSample(t *testing.T) {
|
||||||
|
@ -92,6 +95,7 @@ func TestPostgresMakeConfig(t *testing.T) {
|
||||||
5432,
|
5432,
|
||||||
"Testing POSTGRES",
|
"Testing POSTGRES",
|
||||||
"This is a test of Statup.io!",
|
"This is a test of Statup.io!",
|
||||||
|
"",
|
||||||
"admin",
|
"admin",
|
||||||
"admin",
|
"admin",
|
||||||
nil,
|
nil,
|
||||||
|
@ -105,6 +109,7 @@ func TestPostgresMakeConfig(t *testing.T) {
|
||||||
|
|
||||||
err = DbConnection(configs.Connection)
|
err = DbConnection(configs.Connection)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
InsertDefaultComms()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertPostgresSample(t *testing.T) {
|
func TestInsertPostgresSample(t *testing.T) {
|
||||||
|
@ -130,8 +135,8 @@ func TestSelectCore(t *testing.T) {
|
||||||
|
|
||||||
func TestUser_Create(t *testing.T) {
|
func TestUser_Create(t *testing.T) {
|
||||||
user := &User{
|
user := &User{
|
||||||
Username: "testuserhere",
|
Username: "admin",
|
||||||
Password: "password123",
|
Password: "admin",
|
||||||
Email: "info@testuser.com",
|
Email: "info@testuser.com",
|
||||||
}
|
}
|
||||||
id, err := user.Create()
|
id, err := user.Create()
|
||||||
|
@ -215,7 +220,7 @@ func TestService_Hits(t *testing.T) {
|
||||||
assert.NotNil(t, service)
|
assert.NotNil(t, service)
|
||||||
hits, err := service.Hits()
|
hits, err := service.Hits()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 20, len(hits))
|
assert.Equal(t, 26, len(hits))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestService_LimitedHits(t *testing.T) {
|
func TestService_LimitedHits(t *testing.T) {
|
||||||
|
@ -223,7 +228,7 @@ func TestService_LimitedHits(t *testing.T) {
|
||||||
assert.NotNil(t, service)
|
assert.NotNil(t, service)
|
||||||
hits, err := service.LimitedHits()
|
hits, err := service.LimitedHits()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 20, len(hits))
|
assert.Equal(t, 26, len(hits))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
func Test(t *testing.T) {
|
||||||
|
|
13
setup.go
13
setup.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-yaml/yaml"
|
"github.com/go-yaml/yaml"
|
||||||
"github.com/hunterlong/statup/plugin"
|
"github.com/hunterlong/statup/plugin"
|
||||||
|
"github.com/hunterlong/statup/types"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -20,13 +21,14 @@ type DbConfig struct {
|
||||||
DbPort int `yaml:"port"`
|
DbPort int `yaml:"port"`
|
||||||
Project string `yaml:"-"`
|
Project string `yaml:"-"`
|
||||||
Description string `yaml:"-"`
|
Description string `yaml:"-"`
|
||||||
|
Domain string `yaml:"-"`
|
||||||
Username string `yaml:"-"`
|
Username string `yaml:"-"`
|
||||||
Password string `yaml:"-"`
|
Password string `yaml:"-"`
|
||||||
Error error
|
Error error `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
|
func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if core.ApiKey != "" {
|
if core != nil {
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -42,6 +44,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
password := r.PostForm.Get("password")
|
password := r.PostForm.Get("password")
|
||||||
sample := r.PostForm.Get("sample_data")
|
sample := r.PostForm.Get("sample_data")
|
||||||
description := r.PostForm.Get("description")
|
description := r.PostForm.Get("description")
|
||||||
|
domain := r.PostForm.Get("domain")
|
||||||
|
|
||||||
config := &DbConfig{
|
config := &DbConfig{
|
||||||
dbConn,
|
dbConn,
|
||||||
|
@ -52,6 +55,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
dbPort,
|
dbPort,
|
||||||
project,
|
project,
|
||||||
description,
|
description,
|
||||||
|
domain,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
nil,
|
nil,
|
||||||
|
@ -97,12 +101,12 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func InsertDefaultComms() {
|
func InsertDefaultComms() {
|
||||||
emailer := &Communication{
|
emailer := &types.Communication{
|
||||||
Method: "email",
|
Method: "email",
|
||||||
Removable: false,
|
Removable: false,
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
}
|
}
|
||||||
emailer.Create()
|
Create(emailer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteConfig() {
|
func DeleteConfig() {
|
||||||
|
@ -166,6 +170,7 @@ func (c *DbConfig) Save() error {
|
||||||
[]plugin.Info{},
|
[]plugin.Info{},
|
||||||
[]PluginJSON{},
|
[]PluginJSON{},
|
||||||
[]PluginSelect{},
|
[]PluginSelect{},
|
||||||
|
nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
col := dbSession.Collection("core")
|
col := dbSession.Collection("core")
|
||||||
|
|
|
@ -46,6 +46,7 @@ CREATE TABLE hits (
|
||||||
CREATE TABLE failures (
|
CREATE TABLE failures (
|
||||||
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
issue text,
|
issue text,
|
||||||
|
method text,
|
||||||
service INTEGER NOT NULL,
|
service INTEGER NOT NULL,
|
||||||
created_at TIMESTAMP,
|
created_at TIMESTAMP,
|
||||||
INDEX (id, service),
|
INDEX (id, service),
|
||||||
|
@ -65,7 +66,7 @@ CREATE TABLE communication (
|
||||||
method text,
|
method text,
|
||||||
host text,
|
host text,
|
||||||
port integer,
|
port integer,
|
||||||
user text,
|
username text,
|
||||||
password text,
|
password text,
|
||||||
var1 text,
|
var1 text,
|
||||||
var2 text,
|
var2 text,
|
||||||
|
|
|
@ -64,7 +64,7 @@ CREATE TABLE communication (
|
||||||
method text,
|
method text,
|
||||||
host text,
|
host text,
|
||||||
port integer,
|
port integer,
|
||||||
user text,
|
username text,
|
||||||
password text,
|
password text,
|
||||||
var1 text,
|
var1 text,
|
||||||
var2 text,
|
var2 text,
|
||||||
|
@ -76,7 +76,6 @@ CREATE TABLE communication (
|
||||||
created_at TIMESTAMP
|
created_at TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
CREATE INDEX idx_hits ON hits(service);
|
CREATE INDEX idx_hits ON hits(service);
|
||||||
CREATE INDEX idx_failures ON failures(service);
|
CREATE INDEX idx_failures ON failures(service);
|
||||||
CREATE INDEX idx_checkins ON checkins(service);
|
CREATE INDEX idx_checkins ON checkins(service);
|
|
@ -46,6 +46,7 @@ CREATE TABLE hits (
|
||||||
CREATE TABLE failures (
|
CREATE TABLE failures (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
issue text,
|
issue text,
|
||||||
|
method text,
|
||||||
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
created_at TIMESTAMP
|
created_at TIMESTAMP
|
||||||
);
|
);
|
||||||
|
@ -63,7 +64,7 @@ CREATE TABLE communication (
|
||||||
method text,
|
method text,
|
||||||
host text,
|
host text,
|
||||||
port integer,
|
port integer,
|
||||||
user text,
|
username text,
|
||||||
password text,
|
password text,
|
||||||
var1 text,
|
var1 text,
|
||||||
var2 text,
|
var2 text,
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Communication struct {
|
||||||
|
Id int64 `db:"id,omitempty" json:"id"`
|
||||||
|
Method string `db:"method" json:"method"`
|
||||||
|
Host string `db:"host" json:"host"`
|
||||||
|
Port int `db:"port" json:"port"`
|
||||||
|
Username string `db:"username" 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Email struct {
|
||||||
|
To string
|
||||||
|
Subject string
|
||||||
|
Template string
|
||||||
|
Data interface{}
|
||||||
|
Body string
|
||||||
|
}
|
35
web.go
35
web.go
|
@ -5,6 +5,8 @@ import (
|
||||||
"github.com/fatih/structs"
|
"github.com/fatih/structs"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
|
"github.com/hunterlong/statup/comms"
|
||||||
|
"github.com/hunterlong/statup/types"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -45,6 +47,7 @@ func Router() *mux.Router {
|
||||||
r.Handle("/users/{id}/delete", http.HandlerFunc(UsersDeleteHandler)).Methods("GET")
|
r.Handle("/users/{id}/delete", http.HandlerFunc(UsersDeleteHandler)).Methods("GET")
|
||||||
r.Handle("/settings", http.HandlerFunc(PluginsHandler)).Methods("GET")
|
r.Handle("/settings", http.HandlerFunc(PluginsHandler)).Methods("GET")
|
||||||
r.Handle("/settings", http.HandlerFunc(SaveSettingsHandler)).Methods("POST")
|
r.Handle("/settings", http.HandlerFunc(SaveSettingsHandler)).Methods("POST")
|
||||||
|
r.Handle("/settings/email", http.HandlerFunc(SaveEmailSettingsHandler)).Methods("POST")
|
||||||
r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler))
|
r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler))
|
||||||
r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST")
|
r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST")
|
||||||
r.Handle("/help", http.HandlerFunc(HelpHandler))
|
r.Handle("/help", http.HandlerFunc(HelpHandler))
|
||||||
|
@ -150,7 +153,7 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupHandler(w http.ResponseWriter, r *http.Request) {
|
func SetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if core.ApiKey != "" {
|
if core != nil {
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -245,6 +248,34 @@ func IsAuthenticated(r *http.Request) bool {
|
||||||
return session.Values["authenticated"].(bool)
|
return session.Values["authenticated"].(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SaveEmailSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
auth := IsAuthenticated(r)
|
||||||
|
if !auth {
|
||||||
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
emailer := SelectCommunication(1)
|
||||||
|
|
||||||
|
r.ParseForm()
|
||||||
|
emailer.Host = r.PostForm.Get("host")
|
||||||
|
emailer.Username = r.PostForm.Get("username")
|
||||||
|
emailer.Password = r.PostForm.Get("password")
|
||||||
|
emailer.Port = int(StringInt(r.PostForm.Get("port")))
|
||||||
|
emailer.Var1 = r.PostForm.Get("address")
|
||||||
|
Update(emailer)
|
||||||
|
|
||||||
|
sample := &types.Email{
|
||||||
|
To: "info@socialeck.com",
|
||||||
|
Subject: "Sample Email",
|
||||||
|
Template: "templates/error.html",
|
||||||
|
Body: "okkokkok",
|
||||||
|
}
|
||||||
|
|
||||||
|
comms.AddEmail(sample)
|
||||||
|
|
||||||
|
http.Redirect(w, r, "/settings", http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
func SaveSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
func SaveSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
auth := IsAuthenticated(r)
|
auth := IsAuthenticated(r)
|
||||||
if !auth {
|
if !auth {
|
||||||
|
@ -290,6 +321,8 @@ func PluginsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
core.PluginFields = pluginFields
|
core.PluginFields = pluginFields
|
||||||
|
fmt.Println(core.Communications)
|
||||||
|
|
||||||
ExecuteResponse(w, r, "plugins.html", core)
|
ExecuteResponse(w, r, "plugins.html", core)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue