Add user management interface

This commit is contained in:
Las Zenow 2018-04-08 10:55:13 +00:00
parent 6cd5b1bc5e
commit 6f906ccae4
8 changed files with 124 additions and 8 deletions

View file

@ -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,

View file

@ -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")
}

View file

@ -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":

View file

@ -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(

View file

@ -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")

View file

@ -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
}

View file

@ -72,6 +72,7 @@
<li><a href="/new/"><i class="icon-book"></i> New books</a></li>
{{if eq .Role "admin"}}
<li><a href="/news/edit"><i class="icon-certificate"></i> Edit news</a></li>
<li><a href="/admin/users/"><i class="icon-user"></i> Users admin</a></li>
{{end}}
<li class="divider"></li>
{{end}}

34
templates/user_admin.html Normal file
View file

@ -0,0 +1,34 @@
{{template "header.html" .S}}
<h4>Users:</h4>
<table class="table table-hover">
<thead>
<th>username</th>
<th>role</th>
<th>password</th>
<th>last login</th>
</thead>
<tbody>
{{range .Users}}
<tr>
<td>{{.Username}}</td>
<td><form class="row form-inline" method="POST" action="/admin/users/">
<input type="hidden" id="username" name="username" value="{{.Username}}">
<input type="text" id="role" name="role" value="{{.Role}}">
<button type="submit" class="btn btn-primary">Update</button>
</form>
</td>
<td><form class="row form-inline" method="POST" action="/admin/users/">
<input type="hidden" id="username" name="username" value="{{.Username}}">
<input type="password" id="password" name="password" placeholder="password">
<button type="submit" class="btn btn-primary">Update</button>
</form>
</td>
<td>{{.LastLogin.Format "2006-01-02"}}</td>
</tr>
{{end}}
</tbody>
</table>
{{template "footer.html"}}