mirror of https://github.com/statping/statping
upgrades
parent
dc110c0412
commit
470ffb090a
14
checker.go
14
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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
28
exporter.go
28
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)
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "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">
|
||||
<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>
|
||||
<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%;">
|
||||
|
||||
<tr>
|
||||
<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">
|
||||
<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">
|
||||
|
||||
<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">{{ .Name }} is Offline!</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">
|
||||
Your Statup service named '{{.Name}}' has been triggered with a HTTP status code of '{{.LastStatusCode}}' and is currently offline based on your requirements.
|
||||
</p>
|
||||
|
||||
<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">Last Response</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">
|
||||
{{ .LastResponse }}
|
||||
</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;">
|
||||
<td style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; word-break: break-word;">
|
||||
<a href="/service/{{.Id}}" class="button button--blue" target="_blank" style="-webkit-text-size-adjust: none; background: #3869D4; border-color: #3869d4; border-radius: 3px; border-style: solid; border-width: 10px 18px; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16); box-sizing: border-box; color: #FFF; display: inline-block; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; text-decoration: none;">View Service</a>
|
||||
</td>
|
||||
</table>
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -163,6 +163,20 @@
|
|||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<h3>Last Response</h3>
|
||||
|
||||
<textarea class="form-control" readonly>{{ .LastResponse }}</textarea>
|
||||
|
||||
<div class="form-group row mt-2">
|
||||
<label for="last_status_code" class="col-sm-3 col-form-label">Status Code</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" id="last_status_code" class="form-control" value="{{ .LastStatusCode }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
|
||||
|
|
|
@ -74,6 +74,11 @@
|
|||
<input type="text" name="username" class="form-control" value="{{.Username}}" id="formGroupExampleInput" value="admin" placeholder="admin">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="formGroupExampleInput">Admin Email Address</label>
|
||||
<input type="email" name="email" class="form-control" value="{{.Email}}" id="formGroupExampleInput" placeholder="info@admin.com">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="formGroupExampleInput">Admin Password</label>
|
||||
<input type="password" name="password" class="form-control" value="{{.Password}}" id="formGroupExampleInput" value="admin" placeholder="admin">
|
||||
|
|
4
main.go
4
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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
2
setup.go
2
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()
|
||||
|
|
|
@ -24,5 +24,4 @@ type Email struct {
|
|||
Subject string
|
||||
Template string
|
||||
Data interface{}
|
||||
Body string
|
||||
}
|
||||
|
|
17
users.go
17
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")
|
||||
|
|
20
web.go
20
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)
|
||||
|
|
Loading…
Reference in New Issue