From 6f906ccae4608926d69e702c2797ee7bad6a7fc2 Mon Sep 17 00:00:00 2001 From: Las Zenow Date: Sun, 8 Apr 2018 10:55:13 +0000 Subject: [PATCH] Add user management interface --- lib/database/database.go | 4 ++- lib/database/ro.go | 8 ++++++ lib/database/users.go | 28 +++++++++++++++----- lib/template.go | 1 + lib/trantor.go | 2 ++ lib/user.go | 54 +++++++++++++++++++++++++++++++++++++++ templates/header.html | 1 + templates/user_admin.html | 34 ++++++++++++++++++++++++ 8 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 templates/user_admin.html diff --git a/lib/database/database.go b/lib/database/database.go index a39b5d1..2224270 100644 --- a/lib/database/database.go +++ b/lib/database/database.go @@ -21,7 +21,9 @@ type DB interface { AddRawUser(name string, hpass []byte, salt []byte, role string) error GetRole(name string) (string, error) SetPassword(name string, pass string) error + SetRole(name, role string) error ValidPassword(name string, pass string) bool + ListUsers() ([]User, error) AddNews(text string) error AddRawNews(text string, date time.Time) error GetNews(num int, days int) (news []New, err error) @@ -94,7 +96,7 @@ func (db pgDB) Close() error { } func (db pgDB) create() error { - models := []interface{}{&Book{}, &New{}, &user{}, &Visit{}, &Submission{}} + models := []interface{}{&Book{}, &New{}, &User{}, &Visit{}, &Submission{}} for _, model := range models { options := &orm.CreateTableOptions{ IfNotExists: true, diff --git a/lib/database/ro.go b/lib/database/ro.go index c75e63e..42907dd 100644 --- a/lib/database/ro.go +++ b/lib/database/ro.go @@ -65,6 +65,14 @@ func (db *roDB) SetPassword(name string, pass string) error { return errors.New("RO database") } +func (db *roDB) SetRole(name, role string) error { + return errors.New("RO database") +} + +func (db *roDB) ListUsers() ([]User, error) { + return db.db.ListUsers() +} + func (db *roDB) AddNews(text string) error { return errors.New("RO database") } diff --git a/lib/database/users.go b/lib/database/users.go index 419b930..76a26d0 100644 --- a/lib/database/users.go +++ b/lib/database/users.go @@ -12,7 +12,7 @@ import ( "golang.org/x/crypto/scrypt" ) -type user struct { +type User struct { ID int `sql:"type:serial"` Username string `sql:"type:varchar(255),unique"` Password []byte @@ -25,7 +25,7 @@ func (db *pgDB) AddUser(name string, pass string) error { if !validUserName(name) { return errors.New("Invalid user name") } - num, err := db.sql.Model(&user{}).Where("lower(username) = lower(?)", name).Count() + num, err := db.sql.Model(&User{}).Where("lower(username) = lower(?)", name).Count() if err != nil { log.Error("Error on database checking user ", name, ": ", err) return errors.New("An error happen on the database") @@ -43,7 +43,7 @@ func (db *pgDB) AddUser(name string, pass string) error { } func (db *pgDB) AddRawUser(name string, hpass []byte, salt []byte, role string) error { - u := user{ + u := User{ Username: name, Password: hpass, Salt: salt, @@ -53,13 +53,21 @@ func (db *pgDB) AddRawUser(name string, hpass []byte, salt []byte, role string) } func (db *pgDB) GetRole(name string) (string, error) { - var u user + var u User err := db.sql.Model(&u).Where("username = ?", name).Select() return u.Role, err } +func (db *pgDB) SetRole(name, role string) error { + _, err := db.sql.Model(&User{}). + Set("role = ?", role). + Where("username = ?", name). + Update() + return err +} + func (db *pgDB) ValidPassword(name string, pass string) bool { - var u user + var u User err := db.sql.Model(&u).Where("lower(username) = lower(?)", name).Select() if err != nil { return false @@ -73,7 +81,7 @@ func (db *pgDB) ValidPassword(name string, pass string) bool { return false } - _, err = db.sql.Model(&user{}). + _, err = db.sql.Model(&User{}). Set("last_login = CURRENT_TIMESTAMP"). Where("id = ?", u.ID). Update() @@ -88,13 +96,19 @@ func (db *pgDB) SetPassword(name string, pass string) error { if err != nil { return err } - _, err = db.sql.Model(&user{}). + _, err = db.sql.Model(&User{}). Set("password = ?, salt = ?", hash, salt). Where("username = ?", name). Update() return err } +func (db *pgDB) ListUsers() ([]User, error) { + var users []User + err := db.sql.Model(&users).Select() + return users, err +} + func validUserName(name string) bool { switch name { case "", "admin", "webmaster", "postmaster", "info", "root", "news": diff --git a/lib/template.go b/lib/template.go index d1a7801..7f4f452 100644 --- a/lib/template.go +++ b/lib/template.go @@ -73,6 +73,7 @@ func InitTemplate(assetsPath string) *Template { path.Join(templatePath, "dashboard.html"), path.Join(templatePath, "settings.html"), path.Join(templatePath, "help.html"), + path.Join(templatePath, "user_admin.html"), )) t.rss = txt_tmpl.Must(txt_tmpl.ParseFiles( diff --git a/lib/trantor.go b/lib/trantor.go index 76493c6..0c5d5c0 100644 --- a/lib/trantor.go +++ b/lib/trantor.go @@ -196,6 +196,8 @@ func InitRouter(db database.DB, sg *StatsGatherer, assetsPath string) http.Handl r.HandleFunc("/edit/{id:"+idPattern+"}", sg.Gather(editHandler)) r.HandleFunc("/store/{ids:(?:"+idPattern+"/)+}", sg.Gather(storeHandler)) r.HandleFunc("/delete/{ids:(?:"+idPattern+"/)+}", sg.Gather(deleteHandler)) + r.HandleFunc("/admin/users/", sg.Gather(userAdminHandler)).Methods("GET") + r.HandleFunc("/admin/users/", sg.Gather(userAdminPostHandler)).Methods("POST") r.HandleFunc("/news/", sg.Gather(newsHandler)) r.HandleFunc("/news/edit", sg.Gather(editNewsHandler)).Methods("GET") diff --git a/lib/user.go b/lib/user.go index 4657f7e..f86e5d0 100644 --- a/lib/user.go +++ b/lib/user.go @@ -2,6 +2,7 @@ package trantor import ( log "github.com/cihub/seelog" + "gitlab.com/trantor/trantor/lib/database" "net/http" ) @@ -95,3 +96,56 @@ func settingsHandler(h handler) { data.S.Title = "Settings -- " + data.S.Title h.load("settings", data) } + +func userAdminHandler(h handler) { + if !h.sess.IsAdmin() { + notFound(h) + return + } + + users, err := h.db.ListUsers() + if err != nil { + log.Error("Something went wrong listing users: ", err) + notFound(h) + return + } + + var data userAdminData + data.S = GetStatus(h) + data.S.Title = "Users admin -- " + data.S.Title + data.Users = users + h.load("user_admin", data) +} + +func userAdminPostHandler(h handler) { + if !h.sess.IsAdmin() { + notFound(h) + return + } + + username := h.r.FormValue("username") + password := h.r.FormValue("password") + role := h.r.FormValue("role") + if password != "" { + err := h.db.SetPassword(username, password) + if err != nil { + h.sess.Notify("An error ocurred!", err.Error(), "error") + } else { + h.sess.Notify("Password updated!", "", "success") + } + } else if role != "" { + err := h.db.SetRole(username, role) + if err != nil { + h.sess.Notify("An error ocurred!", err.Error(), "error") + } else { + h.sess.Notify("Role updated!", "", "success") + } + } + + userAdminHandler(h) +} + +type userAdminData struct { + S Status + Users []database.User +} diff --git a/templates/header.html b/templates/header.html index 4ce592c..cbc577d 100644 --- a/templates/header.html +++ b/templates/header.html @@ -72,6 +72,7 @@
  • New books
  • {{if eq .Role "admin"}}
  • Edit news
  • +
  • Users admin
  • {{end}}
  • {{end}} diff --git a/templates/user_admin.html b/templates/user_admin.html new file mode 100644 index 0000000..b92fd8b --- /dev/null +++ b/templates/user_admin.html @@ -0,0 +1,34 @@ +{{template "header.html" .S}} + +

    Users:

    + + + + + + + + + +{{range .Users}} + + + + + + +{{end}} + +
    usernamerolepasswordlast login
    {{.Username}}
    + + + +
    +
    + + + +
    +
    {{.LastLogin.Format "2006-01-02"}}
    + +{{template "footer.html"}}