Upgrade users routes to use interfaces

This commit is contained in:
Matthew Dillon 2015-06-19 11:25:42 -08:00
parent 4143e02cfd
commit 3232d4ffbe
2 changed files with 44 additions and 65 deletions

View file

@ -72,8 +72,8 @@ func Handler() http.Handler {
m.Handle("/authenticate", tokenHandler(j.GenerateToken())).Methods("POST") m.Handle("/authenticate", tokenHandler(j.GenerateToken())).Methods("POST")
// Auth routes // Auth routes
m.Handle("/users", j.Secure(http.HandlerFunc(serveUsersList), verifyClaims)).Methods("GET") m.Handle("/users", j.Secure(http.HandlerFunc(handleLister(UserService{})), verifyClaims)).Methods("GET")
m.Handle("/users/{Id:.+}", j.Secure(http.HandlerFunc(serveUser), verifyClaims)).Methods("GET") m.Handle("/users/{Id:.+}", j.Secure(http.HandlerFunc(handleGetter(UserService{})), verifyClaims)).Methods("GET")
// Path-based pattern matching subrouter // Path-based pattern matching subrouter
s := m.PathPrefix("/{genus}").Subrouter() s := m.PathPrefix("/{genus}").Subrouter()

105
users.go
View file

@ -4,11 +4,9 @@ import (
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"errors" "errors"
"net/http" "net/url"
"strconv"
"time" "time"
"github.com/gorilla/mux"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@ -21,7 +19,8 @@ func init() {
DB.AddTableWithName(User{}, "users").SetKeys(true, "Id") DB.AddTableWithName(User{}, "users").SetKeys(true, "Id")
} }
// A User is a person that has administrative access to bactdb. type UserService struct{}
type User struct { type User struct {
Id int64 `json:"id,omitempty"` Id int64 `json:"id,omitempty"`
Email string `db:"email" json:"email"` Email string `db:"email" json:"email"`
@ -33,60 +32,60 @@ type User struct {
DeletedAt NullTime `db:"deleted_at" json:"deletedAt"` DeletedAt NullTime `db:"deleted_at" json:"deletedAt"`
} }
type Users []*User
type UserJSON struct { type UserJSON struct {
User *User `json:"user"` User *User `json:"user"`
} }
type UsersJSON struct { type UsersJSON struct {
Users []*User `json:"users"` Users *Users `json:"users"`
} }
func serveUsersList(w http.ResponseWriter, r *http.Request) { func (u *User) marshal() ([]byte, error) {
return json.Marshal(&UserJSON{User: u})
}
func (u *Users) marshal() ([]byte, error) {
return json.Marshal(&UsersJSON{Users: u})
}
func (u UserService) unmarshal(b []byte) (entity, error) {
var uj UserJSON
err := json.Unmarshal(b, &uj)
return uj.User, err
}
func (u UserService) list(val *url.Values) (entity, error) {
if val == nil {
return nil, errors.New("must provide options")
}
var opt ListOptions var opt ListOptions
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil { if err := schemaDecoder.Decode(&opt, *val); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) return nil, err
return
} }
users, err := dbGetUsers(&opt) users := make(Users, 0)
if err != nil { sql := `SELECT * FROM users;`
http.Error(w, err.Error(), http.StatusInternalServerError) if err := DBH.Select(&users, sql); err != nil {
return return nil, err
} }
if users == nil { return &users, nil
users = []*User{}
}
data, err := json.Marshal(UsersJSON{Users: users})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Write(data)
} }
func serveUser(w http.ResponseWriter, r *http.Request) { func (u UserService) get(id int64, genus string) (entity, error) {
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0) var user User
if err != nil { q := `SELECT * FROM users WHERE id=$1;`
http.Error(w, err.Error(), http.StatusInternalServerError) if err := DBH.SelectOne(&user, q, id); err != nil {
return if err == sql.ErrNoRows {
return nil, ErrUserNotFound
}
return nil, err
} }
return &user, nil
user, err := dbGetUser(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data, err := json.Marshal(UserJSON{User: user})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Write(data)
} }
// for thermokarst/jwt: authentication callback
func dbAuthenticate(email string, password string) error { func dbAuthenticate(email string, password string) error {
var user User var user User
q := `SELECT * FROM users WHERE lower(email)=lower($1);` q := `SELECT * FROM users WHERE lower(email)=lower($1);`
@ -99,27 +98,7 @@ func dbAuthenticate(email string, password string) error {
return nil return nil
} }
func dbGetUsers(opt *ListOptions) ([]*User, error) { // for thermokarst/jwt: setting user in claims bundle
var users []*User
sql := `SELECT * FROM users;`
if err := DBH.Select(&users, sql); err != nil {
return nil, err
}
return users, nil
}
func dbGetUser(id int64) (*User, error) {
var user User
q := `SELECT * FROM users WHERE id=$1;`
if err := DBH.SelectOne(&user, q, id); err != nil {
if err == sql.ErrNoRows {
return nil, ErrUserNotFound
}
return nil, err
}
return &user, nil
}
func dbGetUserByEmail(email string) (*User, error) { func dbGetUserByEmail(email string) (*User, error) {
var user User var user User
q := `SELECT * FROM users WHERE lower(email)=lower($1);` q := `SELECT * FROM users WHERE lower(email)=lower($1);`