Add API handler to fetch user by username

This commit is contained in:
Frédéric Guillot 2017-12-26 12:10:48 -08:00
parent d5b8f2fb88
commit c3c27e3637
6 changed files with 115 additions and 23 deletions

2
Gopkg.lock generated
View File

@ -41,7 +41,7 @@
branch = "master"
name = "github.com/miniflux/miniflux-go"
packages = ["."]
revision = "60d72460e62282aa90cb43fa3a87596900b87678"
revision = "3d654932d84b6afdbd5e66b34b08392f62229e61"
[[projects]]
name = "github.com/tdewolff/minify"

View File

@ -17,7 +17,7 @@ import (
)
const (
testBaseURL = "http://127.0.0.1:8080"
testBaseURL = "http://127.0.0.1:8080/"
testAdminUsername = "admin"
testAdminPassword = "test123"
testStandardPassword = "secret"
@ -136,7 +136,7 @@ func TestRemoveUser(t *testing.T) {
}
}
func TestGetUser(t *testing.T) {
func TestGetUserByID(t *testing.T) {
username := getRandomUsername()
client := miniflux.NewClient(testBaseURL, testAdminUsername, testAdminPassword)
user, err := client.CreateUser(username, testStandardPassword, false)
@ -144,7 +144,63 @@ func TestGetUser(t *testing.T) {
t.Fatal(err)
}
user, err = client.User(user.ID)
_, err = client.UserByID(99999)
if err == nil {
t.Fatal(`Should returns a 404`)
}
user, err = client.UserByID(user.ID)
if err != nil {
t.Fatal(err)
}
if user.ID == 0 {
t.Fatalf(`Invalid userID, got "%v"`, user.ID)
}
if user.Username != username {
t.Fatalf(`Invalid username, got "%v" instead of "%v"`, user.Username, username)
}
if user.Password != "" {
t.Fatalf(`Invalid password, got "%v"`, user.Password)
}
if user.Language != "en_US" {
t.Fatalf(`Invalid language, got "%v"`, user.Language)
}
if user.Theme != "default" {
t.Fatalf(`Invalid theme, got "%v"`, user.Theme)
}
if user.Timezone != "UTC" {
t.Fatalf(`Invalid timezone, got "%v"`, user.Timezone)
}
if user.IsAdmin {
t.Fatalf(`Invalid role, got "%v"`, user.IsAdmin)
}
if user.LastLoginAt != nil {
t.Fatalf(`Invalid last login date, got "%v"`, user.LastLoginAt)
}
}
func TestGetUserByUsername(t *testing.T) {
username := getRandomUsername()
client := miniflux.NewClient(testBaseURL, testAdminUsername, testAdminPassword)
user, err := client.CreateUser(username, testStandardPassword, false)
if err != nil {
t.Fatal(err)
}
_, err = client.UserByUsername("missinguser")
if err == nil {
t.Fatal(`Should returns a 404`)
}
user, err = client.UserByUsername(username)
if err != nil {
t.Fatal(err)
}
@ -256,7 +312,7 @@ func TestCannotGetUserAsNonAdmin(t *testing.T) {
}
client = miniflux.NewClient(testBaseURL, username, testStandardPassword)
_, err = client.User(user.ID)
_, err = client.UserByID(user.ID)
if err == nil {
t.Fatal(`Standard users should not be able to get any users`)
}

View File

@ -88,8 +88,8 @@ func (c *Controller) UpdateUser(ctx *core.Context, request *core.Request, respon
response.JSON().Created(originalUser)
}
// GetUsers is the API handler to get the list of users.
func (c *Controller) GetUsers(ctx *core.Context, request *core.Request, response *core.Response) {
// Users is the API handler to get the list of users.
func (c *Controller) Users(ctx *core.Context, request *core.Request, response *core.Response) {
if !ctx.IsAdminUser() {
response.JSON().Forbidden()
return
@ -104,8 +104,8 @@ func (c *Controller) GetUsers(ctx *core.Context, request *core.Request, response
response.JSON().Standard(users)
}
// GetUser is the API handler to fetch the given user.
func (c *Controller) GetUser(ctx *core.Context, request *core.Request, response *core.Response) {
// UserByID is the API handler to fetch the given user by the ID.
func (c *Controller) UserByID(ctx *core.Context, request *core.Request, response *core.Response) {
if !ctx.IsAdminUser() {
response.JSON().Forbidden()
return
@ -131,6 +131,28 @@ func (c *Controller) GetUser(ctx *core.Context, request *core.Request, response
response.JSON().Standard(user)
}
// UserByUsername is the API handler to fetch the given user by the username.
func (c *Controller) UserByUsername(ctx *core.Context, request *core.Request, response *core.Response) {
if !ctx.IsAdminUser() {
response.JSON().Forbidden()
return
}
username := request.StringParam("username", "")
user, err := c.store.UserByUsername(username)
if err != nil {
response.JSON().BadRequest(errors.New("Unable to fetch this user from the database"))
return
}
if user == nil {
response.JSON().NotFound(errors.New("User not found"))
return
}
response.JSON().Standard(user)
}
// RemoveUser is the API handler to remove an existing user.
func (c *Controller) RemoveUser(ctx *core.Context, request *core.Request, response *core.Response) {
if !ctx.IsAdminUser() {

View File

@ -49,10 +49,11 @@ func getRoutes(cfg *config.Config, store *storage.Storage, feedHandler *feed.Han
router.Handle("/fever/", feverHandler.Use(feverController.Handler))
router.Handle("/v1/users", apiHandler.Use(apiController.CreateUser)).Methods("POST")
router.Handle("/v1/users", apiHandler.Use(apiController.GetUsers)).Methods("GET")
router.Handle("/v1/users/{userID}", apiHandler.Use(apiController.GetUser)).Methods("GET")
router.Handle("/v1/users/{userID}", apiHandler.Use(apiController.UpdateUser)).Methods("PUT")
router.Handle("/v1/users/{userID}", apiHandler.Use(apiController.RemoveUser)).Methods("DELETE")
router.Handle("/v1/users", apiHandler.Use(apiController.Users)).Methods("GET")
router.Handle("/v1/users/{userID:[0-9]+}", apiHandler.Use(apiController.UserByID)).Methods("GET")
router.Handle("/v1/users/{userID:[0-9]+}", apiHandler.Use(apiController.UpdateUser)).Methods("PUT")
router.Handle("/v1/users/{userID:[0-9]+}", apiHandler.Use(apiController.RemoveUser)).Methods("DELETE")
router.Handle("/v1/users/{username}", apiHandler.Use(apiController.UserByUsername)).Methods("GET")
router.Handle("/v1/categories", apiHandler.Use(apiController.CreateCategory)).Methods("POST")
router.Handle("/v1/categories", apiHandler.Use(apiController.GetCategories)).Methods("GET")

View File

@ -33,8 +33,8 @@ func (c *Client) Users() (Users, error) {
return users, nil
}
// User returns a single user.
func (c *Client) User(userID int64) (*User, error) {
// UserByID returns a single user.
func (c *Client) UserByID(userID int64) (*User, error) {
body, err := c.request.Get(fmt.Sprintf("/v1/users/%d", userID))
if err != nil {
return nil, err
@ -50,6 +50,23 @@ func (c *Client) User(userID int64) (*User, error) {
return &user, nil
}
// UserByUsername returns a single user.
func (c *Client) UserByUsername(username string) (*User, error) {
body, err := c.request.Get(fmt.Sprintf("/v1/users/%s", username))
if err != nil {
return nil, err
}
defer body.Close()
var user User
decoder := json.NewDecoder(body)
if err := decoder.Decode(&user); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
return &user, nil
}
// CreateUser creates a new user in the system.
func (c *Client) CreateUser(username, password string, isAdmin bool) (*User, error) {
body, err := c.request.Post("/v1/users", &User{Username: username, Password: password, IsAdmin: isAdmin})

View File

@ -55,6 +55,10 @@ func (r *request) Delete(path string) (io.ReadCloser, error) {
}
func (r *request) execute(method, path string, data interface{}) (io.ReadCloser, error) {
if r.endpoint[len(r.endpoint)-1:] == "/" {
r.endpoint = r.endpoint[:len(r.endpoint)-1]
}
u, err := url.Parse(r.endpoint + path)
if err != nil {
return nil, err
@ -126,11 +130,3 @@ func (r *request) toJSON(v interface{}) []byte {
return b
}
func newRequest(endpoint, username, password string) *request {
return &request{
endpoint: endpoint,
username: username,
password: password,
}
}