Initial commit
This commit is contained in:
commit
10993b9209
|
|
@ -0,0 +1,3 @@
|
|||
mini-beieli-web
|
||||
nohup.out
|
||||
database/
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# mini-beieli-web - Bienenstock Ueberwachung
|
||||
|
||||
Webapplikation, geschrieben in Golang.
|
||||
|
||||
Autor: Joerg Lehmann, nbit Informatik GmbH
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/gorilla/securecookie"
|
||||
"net/http"
|
||||
"fmt"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// cookie handling
|
||||
|
||||
var cookieHandler = securecookie.New(
|
||||
securecookie.GenerateRandomKey(64),
|
||||
securecookie.GenerateRandomKey(32))
|
||||
|
||||
func getUserName(request *http.Request) (userName string) {
|
||||
if cookie, err := request.Cookie("session"); err == nil {
|
||||
cookieValue := make(map[string]string)
|
||||
if err = cookieHandler.Decode("session", cookie.Value, &cookieValue); err == nil {
|
||||
userName = cookieValue["name"]
|
||||
}
|
||||
}
|
||||
return userName
|
||||
}
|
||||
|
||||
func getUserNameHash(request *http.Request) (userName string) {
|
||||
if cookie, err := request.Cookie("session"); err == nil {
|
||||
cookieValue := make(map[string]string)
|
||||
if err = cookieHandler.Decode("session", cookie.Value, &cookieValue); err == nil {
|
||||
userName = cookieValue["name"]
|
||||
}
|
||||
}
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(userName))
|
||||
return hex.EncodeToString(hasher.Sum(nil))
|
||||
}
|
||||
|
||||
func setSession(userName string, response http.ResponseWriter) {
|
||||
value := map[string]string{
|
||||
"name": userName,
|
||||
}
|
||||
if encoded, err := cookieHandler.Encode("session", value); err == nil {
|
||||
cookie := &http.Cookie{
|
||||
Name: "session",
|
||||
Value: encoded,
|
||||
Path: "/",
|
||||
}
|
||||
http.SetCookie(response, cookie)
|
||||
}
|
||||
}
|
||||
|
||||
func clearSession(response http.ResponseWriter) {
|
||||
cookie := &http.Cookie{
|
||||
Name: "session",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
MaxAge: -1,
|
||||
}
|
||||
http.SetCookie(response, cookie)
|
||||
}
|
||||
|
||||
// login handler
|
||||
|
||||
func loginHandler(response http.ResponseWriter, request *http.Request) {
|
||||
name := request.FormValue("email")
|
||||
pass := request.FormValue("password")
|
||||
redirectTarget := "/invalid_login.html"
|
||||
//if name != "" && pass != "" {
|
||||
if checkLoginCredentials(name,pass) {
|
||||
// .. check credentials ..
|
||||
logit(fmt.Sprintf("loginHandler: successful login for User %s",name))
|
||||
setSession(name, response)
|
||||
updateLoginTime(name)
|
||||
redirectTarget = "/scales.html"
|
||||
} else {
|
||||
logit(fmt.Sprintf("loginHandler: invalid login for User %s",name))
|
||||
}
|
||||
http.Redirect(response, request, redirectTarget, 302)
|
||||
}
|
||||
|
||||
|
||||
// resetPassword handler
|
||||
|
||||
func resetPasswordHandler(response http.ResponseWriter, request *http.Request) {
|
||||
name := request.FormValue("email")
|
||||
pass := request.FormValue("password")
|
||||
redirectTarget := "/"
|
||||
logit(fmt.Sprintf("resetPasswordHandler: request for User %s",name))
|
||||
if name != "" && pass != "" {
|
||||
if checkUserAvailable(name) {
|
||||
http.Redirect(response, request, "/user_does_not_exist.html", 302)
|
||||
} else {
|
||||
updateUser(name,pass)
|
||||
http.Redirect(response, request, redirectTarget, 302)
|
||||
}
|
||||
}
|
||||
http.Redirect(response, request, "/error_reset_password.html",302)
|
||||
}
|
||||
|
||||
// setPassword handler
|
||||
|
||||
func setPasswordHandler(response http.ResponseWriter, request *http.Request) {
|
||||
name := getUserName(request)
|
||||
pass := request.FormValue("password")
|
||||
if name != "" && pass != "" {
|
||||
if checkUserAvailable(name) {
|
||||
http.Redirect(response, request, "/user_does_not_exist.html", 302)
|
||||
} else {
|
||||
updateUser(name,pass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// logout handler
|
||||
|
||||
func logoutHandler(response http.ResponseWriter, request *http.Request) {
|
||||
clearSession(response)
|
||||
http.Redirect(response, request, "/", 302)
|
||||
}
|
||||
|
||||
// confirm handler
|
||||
|
||||
func confirmHandler(response http.ResponseWriter, request *http.Request) {
|
||||
confirm_id := request.URL.Query().Get("id")
|
||||
logit(fmt.Sprintf("Confirm ID: %s\n",confirm_id))
|
||||
confirmUser(confirm_id)
|
||||
http.Redirect(response, request, "/", 302)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
func logit(log_message string) {
|
||||
log.Println(log_message)
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"bytes"
|
||||
"net/smtp"
|
||||
)
|
||||
|
||||
func sendEmail(username,confirm_id string) {
|
||||
c, err := smtp.Dial("127.0.0.1:25")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
// Set the sender and recipient.
|
||||
c.Mail("register@mini-beieli.ch")
|
||||
c.Rcpt(username)
|
||||
// Send the email body.
|
||||
wc, err := c.Data()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer wc.Close()
|
||||
mail_message := "To: " + username + `
|
||||
Subject: Passwortaenderung auf https://mini-beieli.ch, bitte bestaetigen
|
||||
|
||||
Lieber Benutzer von mini-beieli.ch
|
||||
|
||||
Sie haben soeben eine Passwortaenderung veranlasst. Bitte klicken Sie folgenden Link,
|
||||
um die Registration abzuschliessen:
|
||||
|
||||
https://mini-beieli.ch/confirm?id=` + confirm_id + `
|
||||
|
||||
Bitte ignorieren Sie diese Meldung, falls die Aenderung nicht von Ihnen angefordert wurde!
|
||||
|
||||
Mit freundlichen Grüssen
|
||||
--
|
||||
mini-beieli.ch`
|
||||
|
||||
buf := bytes.NewBufferString(mail_message)
|
||||
if _, err = buf.WriteTo(wc); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AccountData struct {
|
||||
Full_name string
|
||||
Phone string
|
||||
Address string
|
||||
Zip string
|
||||
City string
|
||||
}
|
||||
|
||||
type Scale struct {
|
||||
Beielipi_id string
|
||||
Beielipi_alias string
|
||||
Id string
|
||||
Alias string
|
||||
My_sms_number string
|
||||
Sms_alarm string
|
||||
Last_alarm string
|
||||
}
|
||||
|
||||
func serveTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
logit("Called URL: "+r.URL.Path)
|
||||
// wennn kein File angegeben ist: index.html
|
||||
if r.URL.Path == "/" {
|
||||
r.URL.Path = "/index.html"
|
||||
}
|
||||
lp := path.Join("templates", "layout.html")
|
||||
fp := path.Join("snippets", r.URL.Path)
|
||||
|
||||
// Return a 404 if the template doesn't exist
|
||||
_, err := os.Stat(fp)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
logit("URL not found: " + fp)
|
||||
fp = path.Join("snippets", "404.html")
|
||||
}
|
||||
}
|
||||
|
||||
tmpl, err := template.ParseFiles(lp, fp)
|
||||
if err != nil {
|
||||
// Log the detailed error
|
||||
logit(err.Error())
|
||||
// Return a generic "Internal Server Error" message
|
||||
http.Error(w, http.StatusText(500), 500)
|
||||
return
|
||||
}
|
||||
|
||||
var userName = getUserName(r)
|
||||
|
||||
t := time.Now()
|
||||
var datetimestring = t.Format("20060102150405")
|
||||
data := struct {
|
||||
UserName string
|
||||
DateTimeString string
|
||||
} {
|
||||
userName,
|
||||
datetimestring,
|
||||
}
|
||||
|
||||
if err := tmpl.ExecuteTemplate(w, "layout", &data); err != nil {
|
||||
logit(err.Error())
|
||||
http.Error(w, http.StatusText(500), 500)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
initDB()
|
||||
defer closeDB()
|
||||
fs := http.FileServer(http.Dir("static"))
|
||||
http.Handle("/static/", http.StripPrefix("/static/", fs))
|
||||
http.Handle("/favicon.ico", fs)
|
||||
http.HandleFunc("/", serveTemplate)
|
||||
|
||||
http.HandleFunc("/login", loginHandler)
|
||||
http.HandleFunc("/reset_password", resetPasswordHandler)
|
||||
http.HandleFunc("/set_password", setPasswordHandler)
|
||||
http.HandleFunc("/logout", logoutHandler)
|
||||
http.HandleFunc("/confirm", confirmHandler)
|
||||
|
||||
logit("Starting Web Application...")
|
||||
http.ListenAndServe("127.0.0.1:4000", nil)
|
||||
logit("Terminating Web Application...")
|
||||
}
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"encoding/json"
|
||||
"crypto/rand"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
var globalPool *redis.Pool
|
||||
var globalConn redis.Conn
|
||||
|
||||
|
||||
const userPrefix string = "user:"
|
||||
const confirmPrefix string = "confirm:"
|
||||
|
||||
func newPool() *redis.Pool {
|
||||
return &redis.Pool{
|
||||
// Maximum number of idle connections in the pool.
|
||||
MaxIdle: 80,
|
||||
// max number of connections
|
||||
MaxActive: 12000,
|
||||
// Dial is an application supplied function for creating and
|
||||
// configuring a connection.
|
||||
Dial: func() (redis.Conn, error) {
|
||||
c, err := redis.Dial("tcp", ":6379")
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return c, err
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ping tests connectivity for redis (PONG should be returned)
|
||||
func ping(c redis.Conn) error {
|
||||
// Send PING command to Redis
|
||||
// PING command returns a Redis "Simple String"
|
||||
// Use redis.String to convert the interface type to string
|
||||
s, err := redis.String(c.Do("PING"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logit("PING Response = "+s)
|
||||
// Output: PONG
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// User is a simple user struct for this example
|
||||
type User struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
NewPassword string `json:"new_password"`
|
||||
ConfirmId string `json:"confirm_id"`
|
||||
LastLogin string `json:"last_login"`
|
||||
|
||||
}
|
||||
|
||||
func setStruct(c redis.Conn, usr User) error {
|
||||
|
||||
// serialize User object to JSON
|
||||
json, err := json.Marshal(usr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// SET object
|
||||
_, err = c.Do("SET", userPrefix+usr.Email, json)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStruct(c redis.Conn, username string) (User, error) {
|
||||
|
||||
usr := User{}
|
||||
s, err := redis.String(c.Do("GET", userPrefix+username))
|
||||
if err == redis.ErrNil {
|
||||
logit("User does not exist:"+username)
|
||||
} else if err != nil {
|
||||
return usr, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s), &usr)
|
||||
|
||||
return usr, nil
|
||||
|
||||
}
|
||||
|
||||
func initDB() {
|
||||
|
||||
// newPool returns a pointer to a redis.Pool
|
||||
pool := newPool()
|
||||
// get a connection from the pool (redis.Conn)
|
||||
conn := pool.Get()
|
||||
|
||||
globalPool = pool
|
||||
globalConn = conn
|
||||
|
||||
// wir machen einen Connection Test
|
||||
ping(globalConn)
|
||||
|
||||
// Wir legen einen initialen Admin User an, falls es diesen noch nicht gibt
|
||||
if checkUserAvailable("joerg.lehmann@nbit.ch") {
|
||||
insertUser("joerg.lehmann@nbit.ch","changeme123","Y");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func closeDB() {
|
||||
globalConn.Close()
|
||||
globalPool.Close()
|
||||
}
|
||||
|
||||
func checkUserAvailable(username string) bool {
|
||||
logit("checkUserAvailable: User: "+username)
|
||||
_, err := redis.String(globalConn.Do("GET", userPrefix+username))
|
||||
if (err == redis.ErrNil) {
|
||||
logit("User does not exist and is therefore available:"+username)
|
||||
return true
|
||||
} else if err != nil {
|
||||
logit("checkUserAvailable: Error to query Key Value Store")
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func randString(n int) string {
|
||||
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
var bytes = make([]byte, n)
|
||||
rand.Read(bytes)
|
||||
for i, b := range bytes {
|
||||
bytes[i] = alphanum[b % byte(len(alphanum))]
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func insertUser(username,password,is_admin string) {
|
||||
logit("insertUser: "+username)
|
||||
pwd := []byte(password)
|
||||
hashedPassword,err := bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
logit("insertUser: Error with bcrypt.GenerateFromPassword, User: "+username)
|
||||
return
|
||||
}
|
||||
confirm_id := ""
|
||||
|
||||
_, err = globalConn.Do("HMSET", userPrefix+username, "password", string(hashedPassword), "new_password", string(hashedPassword), "confirm_id", confirm_id, "last_login", "")
|
||||
|
||||
if err != nil {
|
||||
logit("insertUser: Error inserting User: "+username)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func updateUser(username,password string) {
|
||||
logit("updateUser: "+username)
|
||||
pwd := []byte(password)
|
||||
hashedPassword,err := bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
logit("updateUser: Error with bcrypt.GenerateFromPassword, User: "+username)
|
||||
return
|
||||
}
|
||||
confirm_id := randString(30)
|
||||
|
||||
_, err = globalConn.Do("HMSET", userPrefix+username, "new_password", string(hashedPassword), "confirm_id", confirm_id)
|
||||
if err != nil {
|
||||
logit("updateUser: Error updateing User: "+username)
|
||||
return
|
||||
}
|
||||
_, err = globalConn.Do("SET", confirmPrefix+confirm_id,username)
|
||||
if err != nil {
|
||||
logit("updateUser: Error inserting confirm_id: "+confirm_id+": "+username)
|
||||
return
|
||||
}
|
||||
|
||||
sendEmail(username,confirm_id)
|
||||
}
|
||||
|
||||
func checkLoginCredentials(username,password string) bool {
|
||||
logit("checkLoginCredentials: called with username,password: "+username+","+password)
|
||||
pwd, err := redis.String(globalConn.Do("HGET", userPrefix+username, "password"))
|
||||
if err == nil {
|
||||
cid, err := redis.String(globalConn.Do("HGET", userPrefix+username, "confirm_id"))
|
||||
if err == nil {
|
||||
logit("checkLoginCredentials: cid: "+cid)
|
||||
if !(err != nil && cid != "") {
|
||||
logit("checkLoginCredentials: pwd: "+pwd)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hashedPassword := []byte(pwd)
|
||||
err = bcrypt.CompareHashAndPassword(hashedPassword, []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func updateLoginTime(username string) {
|
||||
_, err := globalConn.Do("HSET", userPrefix+username, "last_login", time.Now().UTC().Format("2006-01-02 15:04:05"))
|
||||
if err != nil {
|
||||
logit("updateUser: Error updateing User: "+username)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func confirmUser(confirm_id string) {
|
||||
u, err := redis.String(globalConn.Do("GET", confirmPrefix+confirm_id))
|
||||
if err != nil {
|
||||
logit("confirmUser: Error with searching confirm_id: "+confirm_id)
|
||||
return
|
||||
}
|
||||
new_password, err := redis.String(globalConn.Do("HGET", userPrefix+u, "new_password"))
|
||||
if err != nil {
|
||||
logit("confirmUser: Error with getting new_password: "+u)
|
||||
return
|
||||
}
|
||||
_, err = globalConn.Do("HMSET", userPrefix+u, "confirm_id", "", "password", new_password)
|
||||
if err != nil {
|
||||
logit("confirmUser: Error updateing User: "+u)
|
||||
return
|
||||
}
|
||||
_, err = globalConn.Do("DEL", confirmPrefix+confirm_id)
|
||||
if err != nil {
|
||||
logit("confirmUser: Error deleting confirm_id: "+confirm_id)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{{define "body_content"}}
|
||||
<div class="notification is-danger">
|
||||
<strong>Diese Seite existiert nicht</strong>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{{define "body_content"}}
|
||||
<p class="title is-4">Kontakt</p>
|
||||
<p>nbit Informatik GmbH<br />
|
||||
Kirchweg 2<br />
|
||||
3510 Konolfingen<br />
|
||||
<br />
|
||||
+41 31 792 00 40<br />
|
||||
<a href='mailto:i%6Efo@%6Ebit.%63h'>info@nbit.ch</a>
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{{define "header_additions"}}
|
||||
{{end}}
|
||||
{{define "body_content"}}
|
||||
<p class="title is-4">Die etwas andere Bienenstockwaage...</p>
|
||||
<article class="message is-danger">
|
||||
<div class="message-body">
|
||||
Aktuell noch in Entwicklung, kommen Sie später noch einmal vorbei...
|
||||
</div>
|
||||
</article>
|
||||
{{ if ne .UserName "" }}
|
||||
<p>
|
||||
<strong>Ich will weitere bestellen!</strong>
|
||||
<span class="icon"><i class="fa fa-arrow-right"></i></span>
|
||||
Hier geht's zum <a href="/order.html">Bestellformular</a>
|
||||
</p>
|
||||
{{ else }}
|
||||
<p>
|
||||
<strong>Ich will auch eine!</strong>
|
||||
<span class="icon"><i class="fa fa-arrow-right"></i></span>
|
||||
Hier geht's zum <a href="/order.html">Bestellformular</a>
|
||||
</p>
|
||||
<p> </p>
|
||||
<p>
|
||||
<strong>Ich habe bereits eine (oder mehrere)</strong>
|
||||
<span class="icon"><i class="fa fa-arrow-right"></i></span>
|
||||
Hier geht's zum <a href="/login.html">Login</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{{define "body_content"}}
|
||||
<div class="notification is-danger">
|
||||
<strong>Ungültiges Login!</strong>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
{{define "body_content"}}
|
||||
{{ if ne .UserName "" }}
|
||||
Sie sind bereits eingeloggt!
|
||||
{{ else }}
|
||||
<form class="form-signin" id="login-form" action="/login">
|
||||
<div class="column is-auto">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-4">
|
||||
<h1 class="title">Login</h1>
|
||||
<div class="field">
|
||||
<p class="control has-icons-left has-icons-right">
|
||||
<input id="email" name="email" class="input is-success is-focused" type="text" placeholder="Email">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-envelope"></i>
|
||||
</span>
|
||||
<span class="icon is-small is-right">
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p class="control has-icons-left has-icons-right">
|
||||
<input id="password" name="password" class="input" type="password" placeholder="Password">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-lock"></i>
|
||||
</span>
|
||||
<span class="icon is-small is-right">
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="has-text-centered">
|
||||
<a href="/reset_password.html">Passwort vergessen?</a><br/>
|
||||
</div>
|
||||
<br>
|
||||
<div id="errorbox" class="notification is-danger is-size-7-mobile" style="display: none;">
|
||||
</div>
|
||||
<div class="has-text-centered">
|
||||
<input id="login-button" name="login-button" type="submit" class="form-button button is-primary is-centered" value="Anmelden"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{{define "body_content"}}
|
||||
<p class="title is-4">Bestellformular</p>
|
||||
<article class="message is-danger">
|
||||
<div class="message-body">
|
||||
Aktuell noch in Entwicklung, kommen Sie später noch einmal vorbei...
|
||||
</div>
|
||||
</article>
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
{{define "body_content"}}
|
||||
{{ if ne .UserName "" }}
|
||||
Sie sind bereits eingeloggt!
|
||||
{{ else }}
|
||||
<p class="title is-4">Passwort zurücksetzen</p>
|
||||
<div class="notification is-info">
|
||||
<p>Hier können Sie ein neues Passwort setzen. Sie erhalten anschliessend eine Meldung zur Bestätigung zugesendet. Das neue Passwort wird erst gültig, wenn Sie die Bestätigung durchgeführt haben.</p>
|
||||
</div>
|
||||
<form class="form-signin" id="reset-password-form" action="/reset_password">
|
||||
<div class="column is-auto">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-4">
|
||||
<div class="field">
|
||||
<p class="control has-icons-left has-icons-right">
|
||||
<input id="email" name="email" class="input is-success is-focused" type="text" placeholder="Email">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-envelope"></i>
|
||||
</span>
|
||||
<span class="icon is-small is-right">
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p class="control has-icons-left has-icons-right">
|
||||
<input id="password" name="password" class="input" type="password" placeholder="Password">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-lock"></i>
|
||||
</span>
|
||||
<span class="icon is-small is-right">
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<br>
|
||||
<div id="errorbox" class="notification is-danger is-size-7-mobile" style="display: none;">
|
||||
</div>
|
||||
<div class="has-text-centered">
|
||||
<input id="login-button" name="login-button" type="submit" class="form-button button is-primary is-centered" value="Passwort zurücksetzen"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{{define "body_content"}}
|
||||
{{ if ne .UserName "" }}
|
||||
<p>Datenauswertung</p>
|
||||
{{ else }}
|
||||
<h4>Bitte zuerst <a href="login.html">einloggen</a></h4>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{{define "body_content"}}
|
||||
<div class="notification is-danger">
|
||||
<strong>Benutzer existiert nicht!</strong>
|
||||
</div>
|
||||
{{end}}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,29 @@
|
|||
.image.is-10by1 img, .image.is-20by3 img {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.image.is-10by1 {
|
||||
padding-top: 10%;
|
||||
}
|
||||
|
||||
.image.is-20by3 {
|
||||
padding-top: 15%;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 0px 0 5px 0;
|
||||
}
|
||||
|
||||
.signup-box {
|
||||
margin: auto;
|
||||
width: 300px;
|
||||
background: rgba(255,255,255,0.05);
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
border-radius: 10px;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,70 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
$("#email").focus();
|
||||
|
||||
// Check for click events on the navbar burger icon
|
||||
$(".navbar-burger").click(function() {
|
||||
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
|
||||
$(".navbar-burger").toggleClass("is-active");
|
||||
$(".navbar-menu").toggleClass("is-active");
|
||||
|
||||
});
|
||||
|
||||
// Login Button
|
||||
$("#login-button").click(function(e){
|
||||
//alert(true);
|
||||
$("#login-form").submit();
|
||||
});
|
||||
|
||||
// Login Form
|
||||
$("#login-form-blabla").submit(function(e){
|
||||
e.preventDefault();
|
||||
var formData = {
|
||||
next: $("#email").val(),
|
||||
email: $("#email").val(),
|
||||
password: $("#password").val(),
|
||||
csrf_token: $("#csrf_token").val(),
|
||||
next: $("#next").val()
|
||||
};
|
||||
|
||||
//console.log(formData);
|
||||
// send ajax
|
||||
$.ajax({
|
||||
url: '/login', // url where to submit the request
|
||||
type : "POST", // type of action POST || GET
|
||||
dataType : 'json', // data type
|
||||
contentType: 'application/json',
|
||||
data : JSON.stringify(formData), // post data || get data
|
||||
success : function(result) {
|
||||
// you can see the result from the console
|
||||
// tab of the developer tools
|
||||
console.log('SUCCESS');
|
||||
console.log(result);
|
||||
window.location.replace("/");
|
||||
},
|
||||
error: function(result) {
|
||||
//console.log(xhr, resp, text);
|
||||
console.log('ERROR');
|
||||
console.log(result);
|
||||
var errortext = '<ul style="list-style-type:disc">';
|
||||
a = result.responseJSON.response.errors.email;
|
||||
if (a != undefined) {
|
||||
for (i=0; i < a.length; ++i) {
|
||||
errortext = errortext + "<li>" + a[i] + "</li>";
|
||||
}
|
||||
}
|
||||
a = result.responseJSON.response.errors.password;
|
||||
if (a != undefined) {
|
||||
for (i=0; i < a.length; ++i) {
|
||||
errortext = errortext + "<li>" + a[i] + "</li>";
|
||||
}
|
||||
}
|
||||
errortext = errortext + "</ul>";
|
||||
$('#errorbox').html(errortext);
|
||||
$('#errorbox').show();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
[Unit]
|
||||
Description=mini-beieli web service
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=beieli
|
||||
Group=beieli
|
||||
WorkingDirectory=/home/beieli/mini-beieli-web
|
||||
ExecStart=/home/beieli/mini-beieli-web/mini-beieli-web
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
{{define "header_additions"}}{{end}}
|
||||
{{define "layout"}}<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>mini-beieli.ch - die besondere Bienenstockwaage</title>
|
||||
<link rel="stylesheet" href="/static/css/bulma-0.7.4/bulma.min.css">
|
||||
<link rel="stylesheet" href="static/css/mini-beieli-web.css">
|
||||
|
||||
<script defer src="/static/js/fontawesome-5.1.0/all.js"></script>
|
||||
<script src="/static/js/jquery-3.3.1/jquery.min.js"></script>
|
||||
{{template "header_additions" . }}
|
||||
</head>
|
||||
<body>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<figure class="image is-hidden-mobile is-20by3">
|
||||
<img src="/static/images/bees-banner-1000x150.jpg" alt="mini-beieli Banner" >
|
||||
</figure>
|
||||
<figure class="image is-hidden-tablet is-3by1">
|
||||
<img src="/static/images/bees-banner-450x150.jpg" alt="mini-beieli Banner" >
|
||||
</figure>
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item" href="/">
|
||||
<img src="/static/images/bee-logo-28.png" alt="mini-beieli Logo" width="28" height="28">
|
||||
</a>
|
||||
<a role="button" class="navbar-burger" data-target="navMenu" aria-label="menu" aria-expanded="false">
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-menu" id="navMenu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item" href="/">
|
||||
<div style="position:relative">
|
||||
<span class="icon"><i class="fa fa-home"></i></span>
|
||||
<span>Home</span>
|
||||
</div>
|
||||
</a>
|
||||
<a class="navbar-item" href="/contact.html">
|
||||
<div style="position:relative">
|
||||
<span class="icon"><i class="fa fa-address-card"></i></span>
|
||||
<span>Kontakt</span>
|
||||
</div>
|
||||
</a>
|
||||
{{ if ne .UserName "" }}
|
||||
<a class="navbar-item" href="/scales.html">
|
||||
<div style="position:relative">
|
||||
<span class="icon"><i class="fa fa-balance-scale"></i></span>
|
||||
<span>Meine Waagen</span>
|
||||
</div>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
{{ if ne .UserName "" }}
|
||||
<a class="navbar-item" href="/logout">
|
||||
<div style="position:relative">
|
||||
<span class="icon"><i class="fa fa-sign-out-alt"></i></span>
|
||||
<span>Logout {{ .UserName }}</span>
|
||||
</div>
|
||||
</a>
|
||||
{{ else }}
|
||||
<a class="navbar-item" href="/login.html">
|
||||
<div style="position:relative">
|
||||
<span class="icon"><i class="fa fa-sign-in-alt"></i></span>
|
||||
<span>Login</span>
|
||||
</div>
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<hr />
|
||||
{{template "body_content" . }}
|
||||
</div>
|
||||
</section>
|
||||
<script src="/static/js/mini-beieli-web.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
Loading…
Reference in New Issue