mirror of https://github.com/statping/statping
commit
a845f2531a
|
@ -18,7 +18,7 @@ services:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- VERSION=0.29.4
|
- VERSION=0.29.5
|
||||||
- DB_HOST=localhost
|
- DB_HOST=localhost
|
||||||
- DB_USER=travis
|
- DB_USER=travis
|
||||||
- DB_PASS=
|
- DB_PASS=
|
||||||
|
@ -37,6 +37,7 @@ before_deploy:
|
||||||
deploy:
|
deploy:
|
||||||
- provider: releases
|
- provider: releases
|
||||||
api_key: $GH_TOKEN
|
api_key: $GH_TOKEN
|
||||||
|
if: branch = master
|
||||||
file:
|
file:
|
||||||
- "build/statup-osx-x64.tar.gz"
|
- "build/statup-osx-x64.tar.gz"
|
||||||
- "build/statup-osx-x32.tar.gz"
|
- "build/statup-osx-x32.tar.gz"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# update homebrew to newest version by building on travis
|
# update homebrew and cypress testing to newest version by building on travis
|
||||||
body='{ "request": { "branch": "master", "config": { "env": { "VERSION": "'$VERSION'" } } } }'
|
body='{ "request": { "branch": "master", "config": { "env": { "VERSION": "'$VERSION'" } } } }'
|
||||||
|
|
||||||
curl -s -X POST \
|
curl -s -X POST \
|
||||||
|
@ -11,10 +11,18 @@ curl -s -X POST \
|
||||||
-d "$body" \
|
-d "$body" \
|
||||||
https://api.travis-ci.com/repo/hunterlong%2Fstatup-testing/requests
|
https://api.travis-ci.com/repo/hunterlong%2Fstatup-testing/requests
|
||||||
|
|
||||||
#git clone https://$GH_USER:$GH_TOKEN@github.com/hunterlong/homebrew-statup.git
|
# notify Docker hub to built this branch
|
||||||
#cd homebrew-statup
|
if [ "$TRAVIS_BRANCH" == "master" ]
|
||||||
#
|
then
|
||||||
#./build.sh
|
curl -s -X POST \
|
||||||
#cd ../
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
-H "Travis-API-Version: 3" \
|
||||||
|
-H "Authorization: token $TRAVIS_API" \
|
||||||
|
-d "$body" \
|
||||||
|
https://api.travis-ci.com/repo/hunterlong%2Fhomebrew-statup/requests
|
||||||
|
|
||||||
curl -H "Content-Type: application/json" --data '{"source_type": "Branch", "source_name": "'"$TRAVIS_BRANCH"'"}' -X POST $DOCKER > /dev/null
|
curl -H "Content-Type: application/json" --data '{"docker_tag": "latest"}' -X POST $DOCKER
|
||||||
|
else
|
||||||
|
curl -H "Content-Type: application/json" --data '{"source_type": "Branch", "source_name": "'"$TRAVIS_BRANCH"'"}' -X POST $DOCKER > /dev/null
|
||||||
|
fi
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
ENV VERSION=v0.29.4
|
ENV VERSION=v0.29.5
|
||||||
|
|
||||||
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 && \
|
||||||
|
|
|
@ -13,7 +13,7 @@ An easy to use Status Page for your websites and applications. Statup will autom
|
||||||
Statup strives to remain future-proof and remain intact if a failure is created. Your Statup service should not be running on the same instance you're trying to monitor. If your server crashes your Status Page should still remaining online to notify your users of downtime.
|
Statup strives to remain future-proof and remain intact if a failure is created. Your Statup service should not be running on the same instance you're trying to monitor. If your server crashes your Status Page should still remaining online to notify your users of downtime.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img width="80%" src="https://s3-us-west-2.amazonaws.com/gitimgs/statuphead1.png">
|
<img width="80%" src="https://s3-us-west-2.amazonaws.com/gitimgs/statupsiterun.gif">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Lightweight and Fast
|
## Lightweight and Fast
|
||||||
|
@ -27,14 +27,15 @@ Statup is built in Go Language so all you need is the precompile binary based on
|
||||||
Statup will allow you to completely customize your Status Page using SASS styling with easy to use variables. The Docker image actually contains a prebuilt SASS binary so you won't even need to setup anything!
|
Statup will allow you to completely customize your Status Page using SASS styling with easy to use variables. The Docker image actually contains a prebuilt SASS binary so you won't even need to setup anything!
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img width="100%" src="https://s3-us-west-2.amazonaws.com/gitimgs/statupstyler.png">
|
<img width="100%" src="https://s3-us-west-2.amazonaws.com/gitimgs/statupthempicker.gif">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Mobile View is Gorgeous
|
## Mobile View is Gorgeous
|
||||||
Your status page will be optimized for mobile and desktop viewers. Statup has a full width edge to edge view, which you can also edit to meet your requirements.
|
Your status page will be optimized for mobile and desktop viewers. Statup has a full width edge to edge view, which you can also edit to meet your requirements.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img width="40%" src="https://s3-us-west-2.amazonaws.com/gitimgs/statupmob1.jpg">
|
<img width="30%" src="https://s3-us-west-2.amazonaws.com/gitimgs/mobileview.gif">
|
||||||
|
<img width="30%" src="https://s3-us-west-2.amazonaws.com/gitimgs/statupmobile2.gif">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Run on Any Server
|
## Run on Any Server
|
||||||
|
@ -57,7 +58,7 @@ Plugin are created in Golang using the [statup/plugin](https://github.com/hunter
|
||||||
## Easy to use Dashboard
|
## Easy to use Dashboard
|
||||||
Having a straight forward dashboard makes Statup that much better. Monitor your websites and applications with a basic HTTP GET request, or add a POST request with your own JSON to post to the endpoint.
|
Having a straight forward dashboard makes Statup that much better. Monitor your websites and applications with a basic HTTP GET request, or add a POST request with your own JSON to post to the endpoint.
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img width="80%" src="https://s3-us-west-2.amazonaws.com/gitimgs/statupcreat.png">
|
<img width="80%" src="https://s3-us-west-2.amazonaws.com/gitimgs/statupsettingsview.gif">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Exporting Static HTML
|
## Exporting Static HTML
|
||||||
|
|
181
cli.go
181
cli.go
|
@ -4,8 +4,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statup/core"
|
"github.com/hunterlong/statup/core"
|
||||||
"github.com/hunterlong/statup/plugin"
|
"github.com/hunterlong/statup/plugin"
|
||||||
|
"github.com/hunterlong/statup/types"
|
||||||
"github.com/hunterlong/statup/utils"
|
"github.com/hunterlong/statup/utils"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"upper.io/db.v3/sqlite"
|
"upper.io/db.v3/sqlite"
|
||||||
|
@ -111,9 +113,9 @@ func HelpEcho() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlugin(plug plugin.PluginActions) {
|
func TestPlugin(plug plugin.PluginActions) {
|
||||||
RenderBoxes()
|
|
||||||
defer utils.DeleteFile("./.plugin_test.db")
|
defer utils.DeleteFile("./.plugin_test.db")
|
||||||
core.CoreApp.AllPlugins = []plugin.PluginActions{plug}
|
RenderBoxes()
|
||||||
|
|
||||||
info := plug.GetInfo()
|
info := plug.GetInfo()
|
||||||
fmt.Printf("\n" + BRAKER + "\n")
|
fmt.Printf("\n" + BRAKER + "\n")
|
||||||
fmt.Printf(" Plugin Name: %v\n", info.Name)
|
fmt.Printf(" Plugin Name: %v\n", info.Name)
|
||||||
|
@ -123,25 +125,91 @@ func TestPlugin(plug plugin.PluginActions) {
|
||||||
fmt.Printf(" - Route %v - (%v) /%v \n", k+1, r.Method, r.URL)
|
fmt.Printf(" - Route %v - (%v) /%v \n", k+1, r.Method, r.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to create a new Core with example services, hits, failures, users, and default communications
|
||||||
|
FakeSeed(plug)
|
||||||
|
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
fmt.Println(POINT + "Sending 'OnLoad(sqlbuilder.Database)'")
|
||||||
|
core.OnLoad(core.DbSession)
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
fmt.Println(POINT + "Sending 'OnSuccess(Service)'")
|
||||||
|
core.OnSuccess(core.SelectService(1))
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
fmt.Println(POINT + "Sending 'OnFailure(Service, FailureData)'")
|
||||||
|
fakeFailD := core.FailureData{
|
||||||
|
Issue: "No issue, just testing this plugin. This would include HTTP failure information though",
|
||||||
|
}
|
||||||
|
core.OnFailure(core.SelectService(1), fakeFailD)
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
fmt.Println(POINT + "Sending 'OnSettingsSaved(Core)'")
|
||||||
|
fmt.Println(BRAKER)
|
||||||
|
core.OnSettingsSaved(core.CoreApp)
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
fmt.Println(POINT + "Sending 'OnNewService(Service)'")
|
||||||
|
core.OnNewService(core.SelectService(2))
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
fmt.Println(POINT + "Sending 'OnNewUser(User)'")
|
||||||
|
user, _ := core.SelectUser(1)
|
||||||
|
core.OnNewUser(user)
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
fmt.Println(POINT + "Sending 'OnUpdateService(Service)'")
|
||||||
|
srv := core.SelectService(2)
|
||||||
|
srv.Type = "http"
|
||||||
|
srv.Domain = "https://yahoo.com"
|
||||||
|
core.OnUpdateService(srv)
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
fmt.Println(POINT + "Sending 'OnDeletedService(Service)'")
|
||||||
|
core.OnDeletedService(core.SelectService(1))
|
||||||
|
fmt.Println("\n" + BRAKER)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FakeSeed(plug plugin.PluginActions) {
|
||||||
|
var err error
|
||||||
|
core.CoreApp = core.NewCore()
|
||||||
|
|
||||||
|
core.CoreApp.AllPlugins = []plugin.PluginActions{plug}
|
||||||
|
|
||||||
fmt.Printf("\n" + BRAKER)
|
fmt.Printf("\n" + BRAKER)
|
||||||
|
|
||||||
|
fmt.Println("\nCreating a SQLite database for testing, will be deleted automatically...")
|
||||||
|
sqlFake := sqlite.ConnectionURL{
|
||||||
|
Database: "./.plugin_test.db",
|
||||||
|
}
|
||||||
|
core.DbSession, err = sqlite.Open(sqlFake)
|
||||||
|
if err != nil {
|
||||||
|
utils.Log(3, err)
|
||||||
|
}
|
||||||
|
up, _ := core.SqlBox.String("sqlite_up.sql")
|
||||||
|
requests := strings.Split(up, ";")
|
||||||
|
for _, request := range requests {
|
||||||
|
_, err := core.DbSession.Exec(request)
|
||||||
|
if err != nil {
|
||||||
|
utils.Log(2, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Finished creating Test SQLite database")
|
||||||
|
fmt.Println("Inserting example services into test database...")
|
||||||
|
|
||||||
|
core.CoreApp.Name = "Plugin Test"
|
||||||
|
core.CoreApp.Description = "This is a fake Core for testing your plugin"
|
||||||
|
core.CoreApp.Domain = "http://localhost:8080"
|
||||||
|
core.CoreApp.ApiSecret = "0x0x0x0x0"
|
||||||
|
core.CoreApp.ApiKey = "abcdefg12345"
|
||||||
|
|
||||||
fakeSrv := &core.Service{
|
fakeSrv := &core.Service{
|
||||||
Id: 56,
|
|
||||||
Name: "Test Plugin Service",
|
Name: "Test Plugin Service",
|
||||||
Domain: "https://google.com",
|
Domain: "https://google.com",
|
||||||
|
Method: "GET",
|
||||||
}
|
}
|
||||||
|
fakeSrv.Create()
|
||||||
|
|
||||||
fakeFailD := core.FailureData{
|
fakeSrv2 := &core.Service{
|
||||||
Issue: "No issue, just testing this plugin.",
|
Name: "Awesome Plugin Service",
|
||||||
}
|
Domain: "https://netflix.com",
|
||||||
|
Method: "GET",
|
||||||
fakeCore := &core.Core{
|
|
||||||
Name: "Plugin Test",
|
|
||||||
Description: "This is a fake Core for testing your plugin",
|
|
||||||
ApiSecret: "0x0x0x0x0",
|
|
||||||
ApiKey: "abcdefg12345",
|
|
||||||
Services: []*core.Service{fakeSrv},
|
|
||||||
}
|
}
|
||||||
|
fakeSrv2.Create()
|
||||||
|
|
||||||
fakeUser := &core.User{
|
fakeUser := &core.User{
|
||||||
Id: 6334,
|
Id: 6334,
|
||||||
|
@ -151,54 +219,49 @@ func TestPlugin(plug plugin.PluginActions) {
|
||||||
Admin: true,
|
Admin: true,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
}
|
}
|
||||||
|
fakeUser.Create()
|
||||||
|
|
||||||
fmt.Println("\nCreating a SQLite database for testing, will be deleted automatically...")
|
fakeUser = &core.User{
|
||||||
sqlFake := sqlite.ConnectionURL{
|
Id: 6335,
|
||||||
Database: "./.plugin_test.db",
|
Username: "Billy",
|
||||||
|
Password: "$2a$14$NzT/fLdE3f9iB1Eux2C84O6ZoPhI4NfY0Ke32qllCFo8pMTkUPZzy",
|
||||||
|
Email: "info@awesome.com",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
}
|
}
|
||||||
fakeDb, err := sqlite.Open(sqlFake)
|
fakeUser.Create()
|
||||||
if err != nil {
|
|
||||||
utils.Log(3, err)
|
|
||||||
}
|
|
||||||
up, _ := core.SqlBox.String("sqlite_up.sql")
|
|
||||||
requests := strings.Split(up, ";")
|
|
||||||
for _, request := range requests {
|
|
||||||
_, err := fakeDb.Exec(request)
|
|
||||||
if err != nil {
|
|
||||||
utils.Log(2, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println("Finished creating Test SQLite database, sending events.")
|
|
||||||
|
|
||||||
fmt.Println("\n" + BRAKER)
|
comm := &types.Communication{
|
||||||
fmt.Println(POINT + "Sending 'OnLoad(sqlbuilder.Database)'")
|
Id: 1,
|
||||||
core.OnLoad(fakeDb)
|
Method: "email",
|
||||||
fmt.Println("\n" + BRAKER)
|
}
|
||||||
fmt.Println(POINT + "Sending 'OnSuccess(Service)'")
|
core.Create(comm)
|
||||||
core.OnSuccess(fakeSrv)
|
|
||||||
fmt.Println("\n" + BRAKER)
|
comm2 := &types.Communication{
|
||||||
fmt.Println(POINT + "Sending 'OnFailure(Service, FailureData)'")
|
Id: 2,
|
||||||
core.OnFailure(fakeSrv, fakeFailD)
|
Method: "slack",
|
||||||
fmt.Println("\n" + BRAKER)
|
}
|
||||||
fmt.Println(POINT + "Sending 'OnSettingsSaved(Core)'")
|
core.Create(comm2)
|
||||||
fmt.Println(BRAKER)
|
|
||||||
core.OnSettingsSaved(fakeCore)
|
for i := 0; i <= 50; i++ {
|
||||||
fmt.Println("\n" + BRAKER)
|
dd := core.HitData{
|
||||||
fmt.Println(POINT + "Sending 'OnNewService(Service)'")
|
Latency: rand.Float64(),
|
||||||
core.OnNewService(fakeSrv)
|
}
|
||||||
fmt.Println("\n" + BRAKER)
|
fakeSrv.CreateHit(dd)
|
||||||
fmt.Println(POINT + "Sending 'OnNewUser(User)'")
|
dd = core.HitData{
|
||||||
core.OnNewUser(fakeUser)
|
Latency: rand.Float64(),
|
||||||
fmt.Println("\n" + BRAKER)
|
}
|
||||||
fmt.Println(POINT + "Sending 'OnUpdateService(Service)'")
|
fakeSrv2.CreateHit(dd)
|
||||||
core.OnUpdateService(fakeSrv)
|
fail := core.FailureData{
|
||||||
fmt.Println("\n" + BRAKER)
|
Issue: "This is not an issue, but it would container HTTP response errors.",
|
||||||
fmt.Println(POINT + "Sending 'OnDeletedService(Service)'")
|
}
|
||||||
core.OnDeletedService(fakeSrv)
|
fakeSrv.CreateFailure(fail)
|
||||||
fmt.Println("\n" + BRAKER)
|
|
||||||
|
fail = core.FailureData{
|
||||||
}
|
Issue: "HTTP Status Code 521 did not match 200",
|
||||||
|
}
|
||||||
func FakeSeed() {
|
fakeSrv2.CreateFailure(fail)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Seeding example data is complete, running Plugin Tests")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,8 +244,6 @@ func (u *Service) Create() (int64, error) {
|
||||||
u.Id = uuid.(int64)
|
u.Id = uuid.(int64)
|
||||||
u.stopRoutine = make(chan struct{})
|
u.stopRoutine = make(chan struct{})
|
||||||
CoreApp.Services = append(CoreApp.Services, u)
|
CoreApp.Services = append(CoreApp.Services, u)
|
||||||
go u.CheckQueue()
|
|
||||||
OnNewService(u)
|
|
||||||
return uuid.(int64), err
|
return uuid.(int64), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ func (u *User) Create() (int64, error) {
|
||||||
utils.Log(3, fmt.Sprintf("Failed to create user %v. %v", u.Username, err))
|
utils.Log(3, fmt.Sprintf("Failed to create user %v. %v", u.Username, err))
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
OnNewUser(u)
|
|
||||||
return uuid.(int64), err
|
return uuid.(int64), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,10 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log(3, fmt.Sprintf("Error starting %v check routine. %v", service.Name, err))
|
utils.Log(3, fmt.Sprintf("Error starting %v check routine. %v", service.Name, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
go service.CheckQueue()
|
go service.CheckQueue()
|
||||||
|
core.OnNewService(service)
|
||||||
|
|
||||||
http.Redirect(w, r, "/services", http.StatusSeeOther)
|
http.Redirect(w, r, "/services", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log(2, err)
|
utils.Log(2, err)
|
||||||
}
|
}
|
||||||
|
core.OnNewUser(user)
|
||||||
http.Redirect(w, r, "/users", http.StatusSeeOther)
|
http.Redirect(w, r, "/users", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
main_test.go
14
main_test.go
|
@ -64,6 +64,10 @@ 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+" Create Non Unique Users", func(t *testing.T) {
|
||||||
|
t.SkipNow()
|
||||||
|
RunUser_NonUniqueCreate(t)
|
||||||
|
})
|
||||||
t.Run(dbt+" Select Users", func(t *testing.T) {
|
t.Run(dbt+" Select Users", func(t *testing.T) {
|
||||||
RunUser_SelectAll(t)
|
RunUser_SelectAll(t)
|
||||||
})
|
})
|
||||||
|
@ -275,6 +279,16 @@ func RunUser_Create(t *testing.T) {
|
||||||
assert.Equal(t, int64(2), id)
|
assert.Equal(t, int64(2), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunUser_NonUniqueCreate(t *testing.T) {
|
||||||
|
user := &core.User{
|
||||||
|
Username: "admin",
|
||||||
|
Password: "admin",
|
||||||
|
Email: "info@testuser.com",
|
||||||
|
}
|
||||||
|
_, err := user.Create()
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func RunUser_Delete(t *testing.T) {
|
func RunUser_Delete(t *testing.T) {
|
||||||
user, err := core.SelectUser(2)
|
user, err := core.SelectUser(2)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
|
@ -13,12 +13,13 @@ CREATE TABLE users (
|
||||||
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
username VARCHAR(50),
|
username VARCHAR(50),
|
||||||
password text,
|
password text,
|
||||||
email text,
|
email VARCHAR (50),
|
||||||
api_key VARCHAR(50),
|
api_key VARCHAR(50),
|
||||||
api_secret VARCHAR(50),
|
api_secret VARCHAR(50),
|
||||||
administrator BOOL NOT NULL DEFAULT '0',
|
administrator BOOL NOT NULL DEFAULT '0',
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
INDEX (id)
|
INDEX (id),
|
||||||
|
UNIQUE (username, email)
|
||||||
);
|
);
|
||||||
CREATE TABLE services (
|
CREATE TABLE services (
|
||||||
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
|
|
@ -12,9 +12,9 @@ CREATE TABLE core (
|
||||||
|
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
username text,
|
username VARCHAR (50) UNIQUE,
|
||||||
password text,
|
password text,
|
||||||
email text,
|
email VARCHAR (50) UNIQUE,
|
||||||
api_key text,
|
api_key text,
|
||||||
api_secret text,
|
api_secret text,
|
||||||
administrator bool,
|
administrator bool,
|
||||||
|
|
|
@ -18,7 +18,8 @@ CREATE TABLE users (
|
||||||
api_key text,
|
api_key text,
|
||||||
api_secret text,
|
api_secret text,
|
||||||
administrator bool,
|
administrator bool,
|
||||||
created_at DATETIME
|
created_at DATETIME,
|
||||||
|
UNIQUE (username, email)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE services (
|
CREATE TABLE services (
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
<div class="container col-md-7 col-sm-12 mt-md-5 bg-light">
|
<div class="container col-md-7 col-sm-12 mt-md-5 bg-light">
|
||||||
|
|
||||||
<div class="col-12 mt-3">
|
<div class="col-8 offset-2 mt-3">
|
||||||
|
|
||||||
{{ if .Error }}
|
{{ if .Error }}
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
|
@ -35,9 +35,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-12">
|
||||||
<button type="submit" class="btn btn-primary btn-block d-block d-md-none">Sign in</button>
|
<button type="submit" class="btn btn-primary btn-block">Sign in</button>
|
||||||
<button type="submit" class="btn btn-primary d-none d-md-block">Sign in</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Reference in New Issue