mirror of https://github.com/statping/statping
commit
7079a41c6a
|
@ -18,7 +18,7 @@ services:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- VERSION=0.29.7
|
- VERSION=0.29.8
|
||||||
- DB_HOST=localhost
|
- DB_HOST=localhost
|
||||||
- DB_USER=travis
|
- DB_USER=travis
|
||||||
- DB_PASS=
|
- DB_PASS=
|
||||||
|
@ -65,8 +65,9 @@ before_script:
|
||||||
- go get
|
- go get
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then /bin/bash -c .travis/compile.sh; fi
|
- /bin/bash -c .travis/compile.sh
|
||||||
- go test -v -covermode=count -coverprofile=coverage.out && $GOPATH/bin/goveralls -coverprofile=coverage.out -service=travis -repotoken $COVERALLS
|
- go test -v -covermode=count -coverprofile=coverage.out
|
||||||
|
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then $GOPATH/bin/goveralls -coverprofile=coverage.out -service=travis -repotoken $COVERALLS; fi
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then travis_wait 30 docker pull karalabe/xgo-latest; fi
|
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then travis_wait 30 docker pull karalabe/xgo-latest; fi
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
ENV VERSION=v0.29.7
|
ENV VERSION=v0.29.8
|
||||||
|
|
||||||
RUN apk --no-cache add libstdc++ ca-certificates
|
RUN apk --no-cache add libstdc++ ca-certificates
|
||||||
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \
|
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \
|
||||||
|
|
|
@ -32,6 +32,13 @@ func (u *User) Delete() error {
|
||||||
return user.Delete()
|
return user.Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) Update() error {
|
||||||
|
u.CreatedAt = time.Now()
|
||||||
|
col := DbSession.Collection("users")
|
||||||
|
user := col.Find("id", u.Id)
|
||||||
|
return user.Update(u)
|
||||||
|
}
|
||||||
|
|
||||||
func (u *User) Create() (int64, error) {
|
func (u *User) Create() (int64, error) {
|
||||||
u.CreatedAt = time.Now()
|
u.CreatedAt = time.Now()
|
||||||
u.Password = utils.HashPassword(u.Password)
|
u.Password = utils.HashPassword(u.Password)
|
||||||
|
|
|
@ -29,9 +29,10 @@ func Router() *mux.Router {
|
||||||
r.Handle("/service/{id}/delete_failures", http.HandlerFunc(ServicesDeleteFailuresHandler)).Methods("GET")
|
r.Handle("/service/{id}/delete_failures", http.HandlerFunc(ServicesDeleteFailuresHandler)).Methods("GET")
|
||||||
r.Handle("/service/{id}/checkin", http.HandlerFunc(CheckinCreateUpdateHandler)).Methods("POST")
|
r.Handle("/service/{id}/checkin", http.HandlerFunc(CheckinCreateUpdateHandler)).Methods("POST")
|
||||||
r.Handle("/users", http.HandlerFunc(UsersHandler)).Methods("GET")
|
r.Handle("/users", http.HandlerFunc(UsersHandler)).Methods("GET")
|
||||||
r.Handle("/user/{id}", http.HandlerFunc(UsersHandler)).Methods("GET")
|
|
||||||
r.Handle("/users", http.HandlerFunc(CreateUserHandler)).Methods("POST")
|
r.Handle("/users", http.HandlerFunc(CreateUserHandler)).Methods("POST")
|
||||||
r.Handle("/users/{id}/delete", http.HandlerFunc(UsersDeleteHandler)).Methods("GET")
|
r.Handle("/user/{id}", http.HandlerFunc(UsersEditHandler)).Methods("GET")
|
||||||
|
r.Handle("/user/{id}", http.HandlerFunc(UpdateUserHandler)).Methods("POST")
|
||||||
|
r.Handle("/user/{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/css", http.HandlerFunc(SaveSASSHandler)).Methods("POST")
|
r.Handle("/settings/css", http.HandlerFunc(SaveSASSHandler)).Methods("POST")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/hunterlong/statup/core"
|
"github.com/hunterlong/statup/core"
|
||||||
"github.com/hunterlong/statup/types"
|
"github.com/hunterlong/statup/types"
|
||||||
|
@ -18,13 +19,16 @@ func SessionUser(r *http.Request) *types.User {
|
||||||
var user *types.User
|
var user *types.User
|
||||||
col := core.DbSession.Collection("users")
|
col := core.DbSession.Collection("users")
|
||||||
res := col.Find("id", uuid)
|
res := col.Find("id", uuid)
|
||||||
res.One(&user)
|
err := res.One(&user)
|
||||||
|
if err != nil {
|
||||||
|
utils.Log(3, fmt.Sprintf("cannot fetch user %v", uuid))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
func UsersHandler(w http.ResponseWriter, r *http.Request) {
|
func UsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
auth := IsAuthenticated(r)
|
if !IsAuthenticated(r) {
|
||||||
if !auth {
|
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -32,9 +36,41 @@ func UsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ExecuteResponse(w, r, "users.html", users)
|
ExecuteResponse(w, r, "users.html", users)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UsersEditHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !IsAuthenticated(r) {
|
||||||
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
id, _ := strconv.Atoi(vars["id"])
|
||||||
|
user, _ := core.SelectUser(int64(id))
|
||||||
|
ExecuteResponse(w, r, "user.html", user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !IsAuthenticated(r) {
|
||||||
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.ParseForm()
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
id, _ := strconv.Atoi(vars["id"])
|
||||||
|
user, _ := core.SelectUser(int64(id))
|
||||||
|
|
||||||
|
user.Username = r.PostForm.Get("username")
|
||||||
|
user.Email = r.PostForm.Get("email")
|
||||||
|
user.Admin = (r.PostForm.Get("admin") == "on")
|
||||||
|
password := r.PostForm.Get("password")
|
||||||
|
if password != "##########" {
|
||||||
|
user.Password = utils.HashPassword(password)
|
||||||
|
}
|
||||||
|
user.Update()
|
||||||
|
users, _ := core.SelectAllUsers()
|
||||||
|
ExecuteResponse(w, r, "users.html", users)
|
||||||
|
}
|
||||||
|
|
||||||
func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
|
func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
auth := IsAuthenticated(r)
|
if !IsAuthenticated(r) {
|
||||||
if !auth {
|
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -59,8 +95,7 @@ func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func UsersDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
func UsersDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
auth := IsAuthenticated(r)
|
if !IsAuthenticated(r) {
|
||||||
if !auth {
|
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
27
main_test.go
27
main_test.go
|
@ -64,6 +64,9 @@ func TestRunAll(t *testing.T) {
|
||||||
t.Run(dbt+" Create Users", func(t *testing.T) {
|
t.Run(dbt+" Create Users", func(t *testing.T) {
|
||||||
RunUser_Create(t)
|
RunUser_Create(t)
|
||||||
})
|
})
|
||||||
|
t.Run(dbt+" Update User", func(t *testing.T) {
|
||||||
|
RunUser_Update(t)
|
||||||
|
})
|
||||||
t.Run(dbt+" Create Non Unique Users", func(t *testing.T) {
|
t.Run(dbt+" Create Non Unique Users", func(t *testing.T) {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
RunUser_NonUniqueCreate(t)
|
RunUser_NonUniqueCreate(t)
|
||||||
|
@ -134,6 +137,9 @@ func TestRunAll(t *testing.T) {
|
||||||
t.Run(dbt+" HTTP /users", func(t *testing.T) {
|
t.Run(dbt+" HTTP /users", func(t *testing.T) {
|
||||||
RunUsersHandler(t)
|
RunUsersHandler(t)
|
||||||
})
|
})
|
||||||
|
t.Run(dbt+" HTTP /user/1", func(t *testing.T) {
|
||||||
|
RunUserViewHandler(t)
|
||||||
|
})
|
||||||
t.Run(dbt+" HTTP /services", func(t *testing.T) {
|
t.Run(dbt+" HTTP /services", func(t *testing.T) {
|
||||||
RunServicesHandler(t)
|
RunServicesHandler(t)
|
||||||
})
|
})
|
||||||
|
@ -264,6 +270,7 @@ func RunUser_Create(t *testing.T) {
|
||||||
Username: "admin",
|
Username: "admin",
|
||||||
Password: "admin",
|
Password: "admin",
|
||||||
Email: "info@testuser.com",
|
Email: "info@testuser.com",
|
||||||
|
Admin: true,
|
||||||
}
|
}
|
||||||
id, err := user.Create()
|
id, err := user.Create()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
@ -279,6 +286,17 @@ func RunUser_Create(t *testing.T) {
|
||||||
assert.Equal(t, int64(2), id)
|
assert.Equal(t, int64(2), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunUser_Update(t *testing.T) {
|
||||||
|
user, err := core.SelectUser(1)
|
||||||
|
user.Email = "info@updatedemail.com"
|
||||||
|
assert.Nil(t, err)
|
||||||
|
err = user.Update()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
updatedUser, err := core.SelectUser(1)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "info@updatedemail.com", updatedUser.Email)
|
||||||
|
}
|
||||||
|
|
||||||
func RunUser_NonUniqueCreate(t *testing.T) {
|
func RunUser_NonUniqueCreate(t *testing.T) {
|
||||||
user := &core.User{
|
user := &core.User{
|
||||||
Username: "admin",
|
Username: "admin",
|
||||||
|
@ -481,6 +499,15 @@ func RunUsersHandler(t *testing.T) {
|
||||||
assert.True(t, strings.Contains(rr.Body.String(), "footer"))
|
assert.True(t, strings.Contains(rr.Body.String(), "footer"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunUserViewHandler(t *testing.T) {
|
||||||
|
req, err := http.NewRequest("GET", "/user/1", nil)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
route.ServeHTTP(rr, req)
|
||||||
|
assert.True(t, strings.Contains(rr.Body.String(), "<title>Statup | Users</title>"))
|
||||||
|
assert.True(t, strings.Contains(rr.Body.String(), "footer"))
|
||||||
|
}
|
||||||
|
|
||||||
func RunServicesHandler(t *testing.T) {
|
func RunServicesHandler(t *testing.T) {
|
||||||
req, err := http.NewRequest("GET", "/services", nil)
|
req, err := http.NewRequest("GET", "/services", nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
|
@ -11,6 +11,15 @@ $('form').submit(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$(".confirm-btn").on('click', function() {
|
||||||
|
var r = confirm("Are you sure you want to delete?");
|
||||||
|
if (r == true) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
var ranVar = false;
|
var ranVar = false;
|
||||||
var ranTheme = false;
|
var ranTheme = false;
|
||||||
|
|
|
@ -22,64 +22,42 @@
|
||||||
|
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|
||||||
<h3>Users</h3>
|
<h3>User {{.Username}}</h3>
|
||||||
|
<form action="/user/{{.Id}}" method="POST">
|
||||||
<table class="table table-striped">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">Username</th>
|
|
||||||
<th scope="col"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{{range .}}
|
|
||||||
<tr>
|
|
||||||
<td>{{.Username}}</td>
|
|
||||||
<td class="text-right">
|
|
||||||
<div class="btn-group">
|
|
||||||
<a href="/users/{{.Id}}/delete" class="btn btn-danger">Delete</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3>Create User</h3>
|
|
||||||
<form action="/users" method="POST">
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="username" class="col-sm-4 col-form-label">Username</label>
|
<label for="username" class="col-sm-4 col-form-label">Username</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" name="username" class="form-control" id="username" placeholder="Username" required>
|
<input type="text" name="username" class="form-control" value="{{.Username}}" id="username" placeholder="Username" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<span class="switch">
|
<span class="switch">
|
||||||
<input type="checkbox" name="admin" class="switch" id="switch-normal">
|
<input type="checkbox" name="admin" class="switch" id="switch-normal"{{if .Admin}} checked{{end}}>
|
||||||
<label for="switch-normal">Administrator</label>
|
<label for="switch-normal">Administrator</label>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="email" class="col-sm-4 col-form-label">Email Address</label>
|
<label for="email" class="col-sm-4 col-form-label">Email Address</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="email" name="email" class="form-control" id="email" placeholder="user@domain.com" required>
|
<input type="email" name="email" class="form-control" id="email" value="{{.Email}}" placeholder="user@domain.com" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="password" class="col-sm-4 col-form-label">Password</label>
|
<label for="password" class="col-sm-4 col-form-label">Password</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="password" name="password" class="form-control" id="password" placeholder="Password" required>
|
<input type="password" name="password" class="form-control" id="password" value="##########" placeholder="Password" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="password_confirm" class="col-sm-4 col-form-label">Confirm Password</label>
|
<label for="password_confirm" class="col-sm-4 col-form-label">Confirm Password</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="password" name="password_confirm" class="form-control" id="password_confirm" placeholder="Confirm Password" required>
|
<input type="password" name="password_confirm" class="form-control" id="password_confirm" value="##########" placeholder="Confirm Password" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<button type="submit" class="btn btn-primary btn-block">Create User</button>
|
<input type="hidden" name="user_id" value="{{.Id}}">
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">Update User</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -35,9 +35,10 @@
|
||||||
{{range .}}
|
{{range .}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{.Username}}</td>
|
<td>{{.Username}}</td>
|
||||||
<td class="text-right">
|
<td class="text-right" id="user_{{.Id}}">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a href="/users/{{.Id}}/delete" class="btn btn-danger">Delete</a>
|
<a href="/user/{{.Id}}" class="btn btn-primary">Edit</a>
|
||||||
|
<a href="/user/{{.Id}}/delete" class="btn btn-danger confirm-btn" data-id="user_{{.Id}}">Delete</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
Loading…
Reference in New Issue