Allow edit user info
This commit is contained in:
parent
b4bb23056b
commit
0e2733086e
19
auth/auth.go
19
auth/auth.go
@ -91,6 +91,25 @@ func (a *Authorizer) Login(rw http.ResponseWriter, req *http.Request, username,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Authorizer) RegenSecret(user User, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
cookie, err := a.cookiejar.Get(r, a.cookieName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// genereate secret
|
||||||
|
b, err := bcrypt.GenerateFromPassword([]byte(user.GetHash()), a.cost)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cookie.Values["secret"] = string(b)
|
||||||
|
|
||||||
|
err = cookie.Save(r, w)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Logout remove cookie info
|
// Logout remove cookie info
|
||||||
func (a *Authorizer) Logout(rw http.ResponseWriter, req *http.Request) error {
|
func (a *Authorizer) Logout(rw http.ResponseWriter, req *http.Request) error {
|
||||||
cookie, err := a.cookiejar.Get(req, a.cookieName)
|
cookie, err := a.cookiejar.Get(req, a.cookieName)
|
||||||
|
17
main.go
17
main.go
@ -1,8 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/auth"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/auth"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/movies"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/movies"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/users"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/users"
|
||||||
@ -28,8 +26,7 @@ func main() {
|
|||||||
pgdsn := "postgres://test:test@127.0.0.1:5432/test?sslmode=disable"
|
pgdsn := "postgres://test:test@127.0.0.1:5432/test?sslmode=disable"
|
||||||
db, err := sqlx.Connect("postgres", pgdsn)
|
db, err := sqlx.Connect("postgres", pgdsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Panic(err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
uBackend := &UserBackend{db}
|
uBackend := &UserBackend{db}
|
||||||
authorizer := auth.New(uBackend, "peeper", "cookieName", "cookieKey", 10)
|
authorizer := auth.New(uBackend, "peeper", "cookieName", "cookieKey", 10)
|
||||||
@ -37,16 +34,16 @@ func main() {
|
|||||||
env := web.NewEnv(db, authorizer, log, "./templates")
|
env := web.NewEnv(db, authorizer, log, "./templates")
|
||||||
authMiddleware := auth.NewMiddleware(env.Auth)
|
authMiddleware := auth.NewMiddleware(env.Auth)
|
||||||
|
|
||||||
env.Handle("users.login", "/users/login", users.LoginHandler)
|
env.Handle("users.login", "/users/login", users.Login)
|
||||||
env.Handle("users.logout", "/users/logout", users.LogoutHandler)
|
env.Handle("users.logout", "/users/logout", users.Logout)
|
||||||
env.HandleRole("users.details", "/users/details", users.DetailsHandler, users.UserRole)
|
env.HandleRole("users.details", "/users/details", users.Details, users.UserRole)
|
||||||
|
env.HandleRole("users.edit", "/users/edit", users.Edit, users.UserRole)
|
||||||
|
|
||||||
env.HandleRole("movies.polochon", "/", movies.PolochonMovies, users.UserRole)
|
env.HandleRole("movies.polochon", "/movies/polochon", movies.FromPolochon, users.UserRole)
|
||||||
|
|
||||||
err = env.SetLoginRoute("users.login")
|
err = env.SetLoginRoute("users.login")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Panic(err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n := negroni.Classic()
|
n := negroni.Classic()
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"gitlab.quimbo.fr/odwrtw/papi"
|
"gitlab.quimbo.fr/odwrtw/papi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PolochonMovies(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
|
||||||
v := auth.GetCurrentUser(r)
|
v := auth.GetCurrentUser(r)
|
||||||
user, ok := v.(*users.User)
|
user, ok := v.(*users.User)
|
||||||
|
26
templates/users/details.tmpl
Normal file
26
templates/users/details.tmpl
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div id="user-details" class="content-fluid">
|
||||||
|
|
||||||
|
<div class="col-md-6 col-md-offset-3 col-xs-12">
|
||||||
|
<h2>{{ $.Data.user.Name }}'s informations</h2>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="panel panel-info">
|
||||||
|
<div class="panel-heading">
|
||||||
|
Polochon URL
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">{{ $.Data.polochon.URL }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-info">
|
||||||
|
<div class="panel-heading">
|
||||||
|
Polochon token
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">{{ $.Data.polochon.Token }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a class="btn btn-default pull-left" href="{{ URL "users.edit" }}">Edit</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
43
templates/users/edit.tmpl
Normal file
43
templates/users/edit.tmpl
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="content-fluid">
|
||||||
|
<div class="col-md-6 col-md-offset-3 col-xs-12">
|
||||||
|
<h2>Edit user</h2>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<form accept-charset="UTF-8" action="{{ URL "users.edit" }}" method="POST" class="form-horizontal" id="user">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="PolochonURL">Polochon URL</label>
|
||||||
|
<input autofocus="autofocus" class="form-control" name="PolochonURL" type="text" value="{{ $.Data.polochon.URL }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="PolochonToken">Polochon token</label>
|
||||||
|
<input autofocus="autofocus" class="form-control" name="PolochonToken" type="text" value="{{ $.Data.polochon.Token }}" >
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="Password">Password</label>
|
||||||
|
<input autocomplete="off" class="form-control" name="Password" type="password" value="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="PasswordVerify">Confirm Password</label>
|
||||||
|
<input autocomplete="off" class="form-control" name="PasswordVerify" type="password" value="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input class="btn btn-primary pull-right" type="submit" value="Update">
|
||||||
|
<a class="btn btn-default pull-left" href="{{ URL "users.details" }}">Cancel</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
@ -5,12 +5,15 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/Schema"
|
"github.com/gorilla/Schema"
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/auth"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/auth"
|
||||||
|
"gitlab.quimbo.fr/odwrtw/canape-sql/config"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/web"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoginHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
// Login login user
|
||||||
|
func Login(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
return e.Rends(w, r, "users/login")
|
return e.Rends(w, r, "users/login")
|
||||||
}
|
}
|
||||||
@ -53,21 +56,101 @@ func LoginHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LogoutHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
// Logout just logout
|
||||||
|
func Logout(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
e.Auth.Logout(w, r)
|
e.Auth.Logout(w, r)
|
||||||
route := e.GetLoginRouteGetter()()
|
route := e.GetLoginRouteGetter()()
|
||||||
http.Redirect(w, r, route, http.StatusTemporaryRedirect)
|
http.Redirect(w, r, route, http.StatusTemporaryRedirect)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DetailsHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
// Details show user details
|
||||||
u := auth.GetCurrentUser(r)
|
func Details(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
if u == nil {
|
v := auth.GetCurrentUser(r)
|
||||||
return nil
|
user, ok := v.(*User)
|
||||||
}
|
|
||||||
_, ok := u.(*User)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("Invalid user type")
|
return fmt.Errorf("invalid user type")
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
var polochonConfig config.UserPolochon
|
||||||
|
err := user.GetConfig("polochon", &polochonConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
web.SetData(r, "user", user)
|
||||||
|
web.SetData(r, "polochon", polochonConfig)
|
||||||
|
return env.Rends(w, r, "users/details")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit allow editing user info and configuration
|
||||||
|
func Edit(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
v := auth.GetCurrentUser(r)
|
||||||
|
user, ok := v.(*User)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid user type")
|
||||||
|
}
|
||||||
|
var polochonConfig config.UserPolochon
|
||||||
|
err := user.GetConfig("polochon", &polochonConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Method == "GET" {
|
||||||
|
web.SetData(r, "user", user)
|
||||||
|
web.SetData(r, "polochon", polochonConfig)
|
||||||
|
return env.Rends(w, r, "users/edit")
|
||||||
|
}
|
||||||
|
|
||||||
|
type editForm struct {
|
||||||
|
PolochonURL string
|
||||||
|
PolochonToken string
|
||||||
|
Password string
|
||||||
|
PasswordVerify string
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
form := new(editForm)
|
||||||
|
decoder := schema.NewDecoder()
|
||||||
|
err = decoder.Decode(form, r.PostForm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
polochonConfig.URL = form.PolochonURL
|
||||||
|
polochonConfig.Token = form.PolochonToken
|
||||||
|
|
||||||
|
err = user.SetConfig("polochon", polochonConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.Password != "" || form.PasswordVerify != "" {
|
||||||
|
if form.Password != form.PasswordVerify {
|
||||||
|
// TODO: manage form error
|
||||||
|
}
|
||||||
|
user.Hash, err = env.Auth.GenHash(form.Password)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = user.Update(env.Database)
|
||||||
|
if err != nil {
|
||||||
|
pretty.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = env.Auth.RegenSecret(user, w, r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
web.SetData(r, "user", user)
|
||||||
|
web.SetData(r, "polochon", polochonConfig)
|
||||||
|
return env.Rends(w, r, "users/edit")
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
addUserQuery = `INSERT INTO users (name, hash, admin) VALUES ($1, $2, $3) RETURNING id;`
|
addUserQuery = `INSERT INTO users (name, hash, admin, rawconfig) VALUES ($1, $2, $3, $4) RETURNING id;`
|
||||||
getUserQuery = `SELECT * FROM users WHERE name=$1;`
|
getUserQuery = `SELECT * FROM users WHERE name=$1;`
|
||||||
updateUserQuery = `UPDATE users SET name=:name, hash=:hash, admin=:admin RETURNING *;`
|
updateUserQuery = `UPDATE users SET name=:name, hash=:hash, admin=:admin, rawconfig=:rawconfig WHERE id=:id RETURNING *;`
|
||||||
deleteUseQuery = `DELETE FROM users WHERE id=:id;`
|
deleteUseQuery = `DELETE FROM users WHERE id=:id;`
|
||||||
|
|
||||||
addTokenQuery = `INSERT INTO tokens (value, user_id) VALUES ($1, $2) RETURNING id;`
|
addTokenQuery = `INSERT INTO tokens (value, user_id) VALUES ($1, $2) RETURNING id;`
|
||||||
@ -97,7 +97,7 @@ func Get(q sqlx.Queryer, name string) (*User, error) {
|
|||||||
// Add user to database or raises an error
|
// Add user to database or raises an error
|
||||||
func (u *User) Add(q sqlx.Queryer) error {
|
func (u *User) Add(q sqlx.Queryer) error {
|
||||||
var id string
|
var id string
|
||||||
err := q.QueryRowx(addUserQuery, u.Name, u.Hash, u.Admin).Scan(&id)
|
err := q.QueryRowx(addUserQuery, u.Name, u.Hash, u.Admin, u.RawConfig).Scan(&id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
28
web/env.go
28
web/env.go
@ -34,20 +34,28 @@ type Env struct {
|
|||||||
|
|
||||||
// NewEnv returns a new *Env
|
// NewEnv returns a new *Env
|
||||||
func NewEnv(db *sqlx.DB, auth *auth.Authorizer, log *logrus.Entry, templatesDir string) *Env {
|
func NewEnv(db *sqlx.DB, auth *auth.Authorizer, log *logrus.Entry, templatesDir string) *Env {
|
||||||
return &Env{
|
e := &Env{
|
||||||
Database: db,
|
Database: db,
|
||||||
Log: log,
|
Log: log,
|
||||||
Router: mux.NewRouter(),
|
Router: mux.NewRouter(),
|
||||||
Render: render.New(render.Options{
|
Auth: auth,
|
||||||
Directory: templatesDir,
|
Mode: ProductionMode,
|
||||||
Layout: "layout",
|
|
||||||
Funcs: tmplFuncs,
|
|
||||||
DisableHTTPErrorRendering: true,
|
|
||||||
RequirePartials: true,
|
|
||||||
}),
|
|
||||||
Auth: auth,
|
|
||||||
Mode: ProductionMode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmplFuncs = append(tmplFuncs, map[string]interface{}{
|
||||||
|
"URL": func(name string, pairs ...string) (string, error) {
|
||||||
|
return e.GetURL(name, pairs...)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
e.Render = render.New(render.Options{
|
||||||
|
Directory: templatesDir,
|
||||||
|
Layout: "layout",
|
||||||
|
Funcs: tmplFuncs,
|
||||||
|
DisableHTTPErrorRendering: true,
|
||||||
|
RequirePartials: true,
|
||||||
|
})
|
||||||
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Env) SetLoginRoute(name string) error {
|
func (e *Env) SetLoginRoute(name string) error {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user