Improve user API responses

This commit is contained in:
Frédéric Guillot 2017-12-29 13:53:02 -08:00
parent 7c19febd73
commit 0f053b07a5
3 changed files with 51 additions and 63 deletions

View File

@ -14,13 +14,13 @@ type User struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
IsAdmin bool `json:"is_admin,omitempty"` IsAdmin bool `json:"is_admin"`
Theme string `json:"theme,omitempty"` Theme string `json:"theme"`
Language string `json:"language,omitempty"` Language string `json:"language"`
Timezone string `json:"timezone,omitempty"` Timezone string `json:"timezone"`
EntryDirection string `json:"entry_sorting_direction,omitempty"` EntryDirection string `json:"entry_sorting_direction"`
LastLoginAt *time.Time `json:"last_login_at,omitempty"` LastLoginAt *time.Time `json:"last_login_at,omitempty"`
Extra map[string]string `json:"-"` Extra map[string]string `json:"extra"`
} }
// NewUser returns a new User. // NewUser returns a new User.

View File

@ -39,7 +39,14 @@ func (b *BasicAuthMiddleware) Handler(next http.Handler) http.Handler {
} }
user, err := b.store.UserByUsername(username) user, err := b.store.UserByUsername(username)
if err != nil || user == nil { if err != nil {
logger.Error("[Middleware:BasicAuth] %v", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(errorResponse))
return
}
if user == nil {
logger.Info("[Middleware:BasicAuth] User not found: %s", username) logger.Info("[Middleware:BasicAuth] User not found: %s", username)
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(errorResponse)) w.Write([]byte(errorResponse))

View File

@ -177,78 +177,40 @@ func (s *Storage) UpdateUser(user *model.User) error {
func (s *Storage) UserByID(userID int64) (*model.User, error) { func (s *Storage) UserByID(userID int64) (*model.User, error) {
defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByID] userID=%d", userID)) defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByID] userID=%d", userID))
query := `SELECT query := `SELECT
id, username, is_admin, theme, language, timezone, entry_direction, extra id, username, is_admin, theme, language, timezone, entry_direction, last_login_at, extra
FROM users FROM users
WHERE id = $1` WHERE id = $1`
var user model.User return s.fetchUser(query, userID)
var extra hstore.Hstore
row := s.db.QueryRow(query, userID)
err := row.Scan(
&user.ID,
&user.Username,
&user.IsAdmin,
&user.Theme,
&user.Language,
&user.Timezone,
&user.EntryDirection,
&extra,
)
if err == sql.ErrNoRows {
return nil, nil
} else if err != nil {
return nil, fmt.Errorf("unable to fetch user: %v", err)
}
user.Extra = make(map[string]string)
for key, value := range extra.Map {
if value.Valid {
user.Extra[key] = value.String
}
}
return &user, nil
} }
// UserByUsername finds a user by the username. // UserByUsername finds a user by the username.
func (s *Storage) UserByUsername(username string) (*model.User, error) { func (s *Storage) UserByUsername(username string) (*model.User, error) {
defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByUsername] username=%s", username)) defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByUsername] username=%s", username))
query := `SELECT query := `SELECT
id, username, is_admin, theme, language, timezone, entry_direction id, username, is_admin, theme, language, timezone, entry_direction, last_login_at, extra
FROM users FROM users
WHERE username=LOWER($1)` WHERE username=LOWER($1)`
var user model.User return s.fetchUser(query, username)
row := s.db.QueryRow(query, username)
err := row.Scan(
&user.ID,
&user.Username,
&user.IsAdmin,
&user.Theme,
&user.Language,
&user.Timezone,
&user.EntryDirection,
)
if err == sql.ErrNoRows {
return nil, nil
} else if err != nil {
return nil, fmt.Errorf("unable to fetch user: %v", err)
}
return &user, nil
} }
// UserByExtraField finds a user by an extra field value. // UserByExtraField finds a user by an extra field value.
func (s *Storage) UserByExtraField(field, value string) (*model.User, error) { func (s *Storage) UserByExtraField(field, value string) (*model.User, error) {
defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByExtraField] field=%s", field)) defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByExtraField] field=%s", field))
query := `SELECT query := `SELECT
id, username, is_admin, theme, language, timezone, entry_direction id, username, is_admin, theme, language, timezone, entry_direction, last_login_at, extra
FROM users FROM users
WHERE extra->$1=$2` WHERE extra->$1=$2`
var user model.User return s.fetchUser(query, field, value)
row := s.db.QueryRow(query, field, value) }
err := row.Scan(
func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, error) {
var extra hstore.Hstore
user := model.NewUser()
err := s.db.QueryRow(query, args...).Scan(
&user.ID, &user.ID,
&user.Username, &user.Username,
&user.IsAdmin, &user.IsAdmin,
@ -256,14 +218,23 @@ func (s *Storage) UserByExtraField(field, value string) (*model.User, error) {
&user.Language, &user.Language,
&user.Timezone, &user.Timezone,
&user.EntryDirection, &user.EntryDirection,
&user.LastLoginAt,
&extra,
) )
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, nil return nil, nil
} else if err != nil { } else if err != nil {
return nil, fmt.Errorf("unable to fetch user: %v", err) return nil, fmt.Errorf("unable to fetch user: %v", err)
} }
return &user, nil for key, value := range extra.Map {
if value.Valid {
user.Extra[key] = value.String
}
}
return user, nil
} }
// RemoveUser deletes a user. // RemoveUser deletes a user.
@ -290,8 +261,9 @@ func (s *Storage) RemoveUser(userID int64) error {
// Users returns all users. // Users returns all users.
func (s *Storage) Users() (model.Users, error) { func (s *Storage) Users() (model.Users, error) {
defer helper.ExecutionTime(time.Now(), "[Storage:Users]") defer helper.ExecutionTime(time.Now(), "[Storage:Users]")
query := `SELECT query := `
id, username, is_admin, theme, language, timezone, last_login_at SELECT
id, username, is_admin, theme, language, timezone, entry_direction, last_login_at, extra
FROM users FROM users
ORDER BY username ASC` ORDER BY username ASC`
@ -303,7 +275,8 @@ func (s *Storage) Users() (model.Users, error) {
var users model.Users var users model.Users
for rows.Next() { for rows.Next() {
var user model.User var extra hstore.Hstore
user := model.NewUser()
err := rows.Scan( err := rows.Scan(
&user.ID, &user.ID,
&user.Username, &user.Username,
@ -311,14 +284,22 @@ func (s *Storage) Users() (model.Users, error) {
&user.Theme, &user.Theme,
&user.Language, &user.Language,
&user.Timezone, &user.Timezone,
&user.EntryDirection,
&user.LastLoginAt, &user.LastLoginAt,
&extra,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to fetch users row: %v", err) return nil, fmt.Errorf("unable to fetch users row: %v", err)
} }
users = append(users, &user) for key, value := range extra.Map {
if value.Valid {
user.Extra[key] = value.String
}
}
users = append(users, user)
} }
return users, nil return users, nil