Add Env.Handle and Env.HandleRole functions
This commit is contained in:
parent
054f5103e6
commit
5778fd45df
@ -25,6 +25,7 @@ type UserBackend interface {
|
|||||||
// User interface for user
|
// User interface for user
|
||||||
type User interface {
|
type User interface {
|
||||||
GetHash() string
|
GetHash() string
|
||||||
|
HasRole(string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorizer handle sesssion
|
// Authorizer handle sesssion
|
||||||
|
61
auth/middleware.go
Normal file
61
auth/middleware.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type key int
|
||||||
|
|
||||||
|
const ukey key = 0
|
||||||
|
|
||||||
|
// AuthMiddleware get User from session and put it in context
|
||||||
|
type Middleware struct {
|
||||||
|
authorizer *Authorizer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMiddleware(authorizer *Authorizer) *Middleware {
|
||||||
|
return &Middleware{authorizer}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
user, err := m.authorizer.CurrentUser(w, r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
context.Set(r, ukey, user)
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type MiddlewareRole struct {
|
||||||
|
authorizer *Authorizer
|
||||||
|
role string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMiddlewareRole(authorizer *Authorizer, role string) *MiddlewareRole {
|
||||||
|
return &MiddlewareRole{authorizer, role}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MiddlewareRole) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
user := GetCurrentUser(r)
|
||||||
|
|
||||||
|
if user == nil || !user.HasRole(m.role) {
|
||||||
|
//TODO: redirect to login page and save wanted page
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCurrentUser(r *http.Request) User {
|
||||||
|
u := context.Get(r, ukey)
|
||||||
|
if u == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
user, ok := u.(User)
|
||||||
|
if !ok {
|
||||||
|
panic("Invalid user type")
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
13
main.go
13
main.go
@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/negroni"
|
"github.com/codegangsta/negroni"
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
@ -35,13 +34,17 @@ func main() {
|
|||||||
uBackend := &UserBackend{db}
|
uBackend := &UserBackend{db}
|
||||||
authorizer := auth.New(uBackend, "peeper", "cookieName", "cookieKey", 10)
|
authorizer := auth.New(uBackend, "peeper", "cookieName", "cookieKey", 10)
|
||||||
|
|
||||||
env := web.NewEnv(db, authorizer, log, "/templates")
|
env := web.NewEnv(db, authorizer, log, "./templates")
|
||||||
|
authMiddleware := auth.NewMiddleware(env.Auth)
|
||||||
|
|
||||||
router := mux.NewRouter()
|
env.Handle("users.login", "/users/login", users.LoginHandler)
|
||||||
|
env.Handle("users.logout", "users/logout", users.LogoutHandler)
|
||||||
|
env.HandleRole("users.details", "/users/details", users.DetailsHandler, users.UserRole)
|
||||||
|
|
||||||
router.Handle("/", env.Handler(movies.PolochonMovies))
|
env.HandleRole("movies.polochon", "/", movies.PolochonMovies, users.UserRole)
|
||||||
|
|
||||||
n := negroni.Classic()
|
n := negroni.Classic()
|
||||||
n.UseHandler(router)
|
n.Use(authMiddleware)
|
||||||
|
n.UseHandler(env.Router)
|
||||||
n.Run(":3000")
|
n.Run(":3000")
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/odwrtw/polochon/lib"
|
"github.com/odwrtw/polochon/lib"
|
||||||
"github.com/odwrtw/polochon/modules/tmdb"
|
"github.com/odwrtw/polochon/modules/mock"
|
||||||
|
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/web"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/web"
|
||||||
"gitlab.quimbo.fr/odwrtw/papi"
|
"gitlab.quimbo.fr/odwrtw/papi"
|
||||||
@ -27,7 +27,8 @@ func PolochonMovies(env *web.Env, w http.ResponseWriter, r *http.Request) error
|
|||||||
movies := []*Movie{}
|
movies := []*Movie{}
|
||||||
|
|
||||||
//TODO use configurable detailer
|
//TODO use configurable detailer
|
||||||
detailer, err := tmdb.New(&tmdb.Params{"57be344f84917b3f32c68a678f1482eb"})
|
// detailer, err := tmdb.New(&tmdb.Params{"57be344f84917b3f32c68a678f1482eb"})
|
||||||
|
detailer, _ := mock.NewDetailer(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ CREATE TABLE users (
|
|||||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
name text NOT NULL UNIQUE,
|
name text NOT NULL UNIQUE,
|
||||||
hash text NOT NULL,
|
hash text NOT NULL,
|
||||||
|
admin boolean,
|
||||||
LIKE base INCLUDING DEFAULTS
|
LIKE base INCLUDING DEFAULTS
|
||||||
);
|
);
|
||||||
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users FOR EACH ROW EXECUTE PROCEDURE update_updated_at_column();
|
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users FOR EACH ROW EXECUTE PROCEDURE update_updated_at_column();
|
||||||
|
1
sqltest/001_data.down.sql
Normal file
1
sqltest/001_data.down.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DELETE FROM users;
|
2
sqltest/001_data.up.sql
Normal file
2
sqltest/001_data.up.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
INSERT INTO users (name, hash, admin) VALUES ('test', '$2a$10$DPsyngE6ccXzzE38.JJv3OIpvU/lSjfMyg9CR68F8h6krKIyVJYrW', false);
|
||||||
|
INSERT INTO users (name, hash, admin) VALUES ('admin', '$2a$10$e3564lLAh.0tIHQu8kfzsunViwd56AvGPeUypuCUcE3Vh09RBZci.', true);
|
@ -3,16 +3,8 @@
|
|||||||
<title>My Layout</title>
|
<title>My Layout</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="/vendors/bootstrap/dist/css/bootstrap.min.css">
|
|
||||||
<link rel="stylesheet" type="text/css" href="/vendors/sweetalert/lib/sweet-alert.css">
|
|
||||||
<link rel="stylesheet" href="/css/app.css">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{ template "navbar" $ }}
|
|
||||||
{{ yield }}
|
{{ yield }}
|
||||||
<script src="/vendors/jquery/dist/jquery.min.js"></script>
|
|
||||||
<script src="/vendors/bootstrap/dist/js/bootstrap.min.js"></script>
|
|
||||||
<script src="/vendors/sweetalert/lib/sweet-alert.min.js"></script>
|
|
||||||
<script src="/js/app.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,161 +0,0 @@
|
|||||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="#">Canapé</a>
|
|
||||||
</div>
|
|
||||||
<div class="collapse navbar-collapse">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
|
|
||||||
{{ if .Data.user.IsLogged }}
|
|
||||||
<li {{ if eq .Name "MoviesLibrary" }} class="active" {{ end }}><a href="{{ .Env.GetURL "MoviesLibrary" }}">Movies</a></li>
|
|
||||||
<li {{ if eq .Name "TVShowsLibrary" }} class="active" {{ end }}><a href="{{ .Env.GetURL "TVShowsLibrary" }}">Shows</a></li>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<i class="fa fa-list"></i>
|
|
||||||
Explore
|
|
||||||
<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<li>
|
|
||||||
<a href="{{.Env.GetURL "TVShowsExplore" }}">
|
|
||||||
TVShows
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ .Env.GetURL "MoviesExplore" "sort" "seeds" }}">
|
|
||||||
Movies
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
{{ if .Data.user.IsLogged }}
|
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<i class="fa fa-list"></i>
|
|
||||||
My Watchlist
|
|
||||||
<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<li>
|
|
||||||
<a href="{{.Env.GetURL "TVShowsWichlist" }}">
|
|
||||||
TVShows
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ .Env.GetURL "MoviesWichlist" }}">
|
|
||||||
Movies
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{ if .Data.user.Username }}
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<i class="fa fa-user"></i>
|
|
||||||
{{ .Data.user.Username }}
|
|
||||||
<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<li>
|
|
||||||
<a href="{{ .Env.GetURL "UsersDetails" }}" rel="nofollow">
|
|
||||||
<i class="fa fa-user"></i> My Account
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a data-method="delete" href="{{ .Env.GetURL "logout" }}" rel="nofollow">
|
|
||||||
<i class="fa fa-sign-out"></i> Sign out
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{{ else }}
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
<li>
|
|
||||||
<a href="{{ .Env.GetURL "login" }}">Sign in</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
|
|
||||||
{{ if or (eq $.Name "MoviesLibrary") (eq $.Name "MoviesExplore") }}
|
|
||||||
<div class="hidden-sm hidden-md">
|
|
||||||
<form class="navbar-form navbar-right" role="search" action="{{ $.Env.GetURL "MoviesSearch" }}" method="get">
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" class="form-control" size="13" placeholder="search movies" name="keyword" /><br/>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-default">search</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="visible-sm visible-md">
|
|
||||||
<ul class="nav navbar-nav navbar-right"> <li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<form class="navbar-form" role="search" action="{{ $.Env.GetURL "MoviesSearch" }}" method="get">
|
|
||||||
<li>
|
|
||||||
<input type="text" class="form-control" size="13" placeholder="search movies" name="keyword" /><br/>
|
|
||||||
</li>
|
|
||||||
<button type="submit" class="btn btn-default col-xs-12">search</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
|
|
||||||
{{ if or (eq $.Name "TVShowsLibrary") (eq $.Name "TVShowsExplore") }}
|
|
||||||
<div class="hidden-sm hidden-md">
|
|
||||||
<form class="navbar-form navbar-right" role="search" action="{{ $.Env.GetURL "TVShowsSearch" }}" method="GET">
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" class="form-control" size="13" placeholder="Search TV Shows" name="keyword" /><br/>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-default">Search</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="visible-sm visible-md">
|
|
||||||
<ul class="nav navbar-nav navbar-right"> <li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<form class="navbar-form" role="search" action="{{ $.Env.GetURL "TVShowsSearch" }}" method="GET">
|
|
||||||
<li>
|
|
||||||
<input type="text" class="form-control" size="13" placeholder="Search TV Shows" name="keyword" /><br/>
|
|
||||||
</li>
|
|
||||||
<button type="submit" class="btn btn-default col-xs-12">Search</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
@ -1 +1,5 @@
|
|||||||
hello wolrd
|
<form action="/users/login" method="post">
|
||||||
|
<input type="text" name="Username">
|
||||||
|
<input type="text" name="Password">
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
@ -4,85 +4,55 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/Schema"
|
||||||
"github.com/mholt/binding"
|
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/auth"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/auth"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/web"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FormErrors map[field name]message
|
func LoginHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
type FormErrors map[string]string
|
if r.Method == "GET" {
|
||||||
|
|
||||||
// HandleFormErrors translate binding.Erros to FormErrors
|
|
||||||
func HandleFormErrors(errs binding.Errors) FormErrors {
|
|
||||||
ferrs := FormErrors{}
|
|
||||||
for _, err := range errs {
|
|
||||||
for _, field := range err.FieldNames {
|
|
||||||
if ferrs[field] == "" {
|
|
||||||
ferrs[field] = err.Message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ferrs
|
|
||||||
}
|
|
||||||
|
|
||||||
type loginForm struct {
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *loginForm) FieldMap(r *http.Request) binding.FieldMap {
|
|
||||||
return binding.FieldMap{
|
|
||||||
&f.Username: "username",
|
|
||||||
&f.Password: "password",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *loginForm) Validate(r *http.Request, errs binding.Errors) binding.Errors {
|
|
||||||
if f.Username == "" {
|
|
||||||
errs = append(errs, binding.Error{
|
|
||||||
FieldNames: []string{"username"},
|
|
||||||
Classification: "InvalidValues",
|
|
||||||
Message: "Specify a username",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if f.Password == "" {
|
|
||||||
errs = append(errs, binding.Error{
|
|
||||||
FieldNames: []string{"password"},
|
|
||||||
Classification: "InvalidValues",
|
|
||||||
Message: "Specify a password",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return errs
|
|
||||||
}
|
|
||||||
|
|
||||||
func loginSubmitHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|
||||||
form := new(loginForm)
|
|
||||||
|
|
||||||
errs := binding.Bind(r, form)
|
|
||||||
if errs != nil {
|
|
||||||
formErrs := HandleFormErrors(errs)
|
|
||||||
web.SetData(r, "FormErrors", formErrs)
|
|
||||||
return e.Rends(w, r, "users/login")
|
return e.Rends(w, r, "users/login")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := e.Auth.Login(w, r, form.Username, form.Password)
|
type loginForm struct {
|
||||||
if err != nil {
|
Username string
|
||||||
if err == auth.ErrInvalidPassword || err == ErrUnknownUser {
|
Password string
|
||||||
web.SetData(r, "FormErrors", FormErrors{"password": "Invalid username or password"})
|
|
||||||
return e.Rends(w, r, "users/login")
|
|
||||||
}
|
|
||||||
return web.InternalError(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
err := r.ParseForm()
|
||||||
}
|
|
||||||
|
|
||||||
func userDetailsHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|
||||||
u, err := e.Auth.CurrentUser(w, r)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form := new(loginForm)
|
||||||
|
decoder := schema.NewDecoder()
|
||||||
|
err = decoder.Decode(form, r.PostForm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.Auth.Login(w, r, form.Username, form.Password)
|
||||||
|
if err != nil {
|
||||||
|
if err == auth.ErrInvalidPassword || err == ErrUnknownUser {
|
||||||
|
web.SetData(r, "FormErrors", "Error invalid user or password")
|
||||||
|
return e.Rends(w, r, "users/login")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: redirect to user details or to previous location
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogoutHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
e.Auth.Logout(w, r)
|
||||||
|
//TODO: redirect to login page
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DetailsHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
u := auth.GetCurrentUser(r)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -92,9 +62,3 @@ func userDetailsHandler(e *web.Env, w http.ResponseWriter, r *http.Request) erro
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRoutes adds users routes to the router
|
|
||||||
func SetRoutes(r *mux.Router, e *web.Env) {
|
|
||||||
r.Handle("/login", e.Handler(loginSubmitHandler)).Methods("POST").Name("loginPost")
|
|
||||||
r.Handle("/", e.Handler(userDetailsHandler)).Methods("GET").Name("UserDetails")
|
|
||||||
}
|
|
||||||
|
@ -9,9 +9,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
addUserQuery = `INSERT INTO users (name, hash) VALUES ($1, $2) RETURNING id;`
|
addUserQuery = `INSERT INTO users (name, hash, admin) VALUES ($1, $2, $3) RETURNING id;`
|
||||||
getUserQuery = `SELECT * FROM users WHERE name=$1;`
|
getUserQuery = `SELECT * FROM users WHERE name=$1;`
|
||||||
updateUserQuery = `UPDATE users SET name=:name, hash=:hash RETURNING *;`
|
updateUserQuery = `UPDATE users SET name=:name, hash=:hash, admin=:admin 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;`
|
||||||
@ -20,14 +20,20 @@ const (
|
|||||||
deleteTokenQuery = `DELETE FROM tokens WHERE user_id=$1 AND value=$2;`
|
deleteTokenQuery = `DELETE FROM tokens WHERE user_id=$1 AND value=$2;`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserRole = "user"
|
||||||
|
AdminRole = "admin"
|
||||||
|
)
|
||||||
|
|
||||||
// ErrUnknownUser returned web a user does'nt exist
|
// ErrUnknownUser returned web a user does'nt exist
|
||||||
var ErrUnknownUser = fmt.Errorf("users: user does'nt exist")
|
var ErrUnknownUser = fmt.Errorf("users: user does'nt exist")
|
||||||
|
|
||||||
// User represents an user
|
// User represents an user
|
||||||
type User struct {
|
type User struct {
|
||||||
sqly.BaseModel
|
sqly.BaseModel
|
||||||
Name string
|
Name string
|
||||||
Hash string
|
Hash string
|
||||||
|
Admin bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token represents a token
|
// Token represents a token
|
||||||
@ -52,7 +58,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).Scan(&id)
|
err := q.QueryRowx(addUserQuery, u.Name, u.Hash, u.Admin).Scan(&id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -136,3 +142,10 @@ func (u *User) DeleteToken(ex *sqlx.DB, value string) error {
|
|||||||
func (u *User) GetHash() string {
|
func (u *User) GetHash() string {
|
||||||
return u.Hash
|
return u.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) HasRole(role string) bool {
|
||||||
|
if role == AdminRole && !u.Admin {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
20
web/env.go
20
web/env.go
@ -7,6 +7,7 @@ import (
|
|||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/auth"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/auth"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/codegangsta/negroni"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/unrolled/render"
|
"github.com/unrolled/render"
|
||||||
@ -62,9 +63,17 @@ func (e *Env) GetURL(name string, pairs ...string) (string, error) {
|
|||||||
return URL.String(), nil
|
return URL.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler create a new handler
|
type HandlerFunc func(e *Env, w http.ResponseWriter, r *http.Request) error
|
||||||
func (e *Env) Handler(H func(e *Env, w http.ResponseWriter, r *http.Request) error) Handler {
|
|
||||||
return Handler{e, H}
|
func (e *Env) Handle(name, route string, H HandlerFunc) {
|
||||||
|
e.Router.Handle(route, Handler{e, H})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Env) HandleRole(name, route string, H HandlerFunc, role string) {
|
||||||
|
e.Router.Handle(route, negroni.New(
|
||||||
|
auth.NewMiddlewareRole(e.Auth, role),
|
||||||
|
negroni.Wrap(Handler{e, H}),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Handler struct that takes a configured Env and a function matching our
|
// The Handler struct that takes a configured Env and a function matching our
|
||||||
@ -85,8 +94,3 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.StatusInternalServerError)
|
http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InternalError create a internal error
|
|
||||||
func InternalError(err error) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user