mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
improve user package
- testing more error return codes - remove some errors from code - remove unnecessary code - require a username of at least 3 letters/digits
This commit is contained in:
parent
ed1d7677f2
commit
b570956baf
5 changed files with 204 additions and 90 deletions
|
@ -26,10 +26,7 @@ func RegisterAuthenticate(r *gin.RouterGroup) {
|
||||||
// @Tags authentication
|
// @Tags authentication
|
||||||
// @Param inputUser body user.loginRequest true "loginRequest of user"
|
// @Param inputUser body user.loginRequest true "loginRequest of user"
|
||||||
// @Success 200 {object} docs.ResponseAuthenticate "JSON web token, success status, message and authenticated user object"
|
// @Success 200 {object} docs.ResponseAuthenticate "JSON web token, success status, message and authenticated user object"
|
||||||
// @Failure 400 {object} docs.ResponseError "Bad request"
|
|
||||||
// @Failure 401 {object} docs.ResponseError "Unauthorized"
|
// @Failure 401 {object} docs.ResponseError "Unauthorized"
|
||||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
|
||||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity."
|
|
||||||
// @Failure 500 {object} docs.ResponseError "Internal server error."
|
// @Failure 500 {object} docs.ResponseError "Internal server error."
|
||||||
// @Router /authenticate [post]
|
// @Router /authenticate [post]
|
||||||
func authenticate(c *gin.Context) {
|
func authenticate(c *gin.Context) {
|
||||||
|
@ -37,13 +34,13 @@ func authenticate(c *gin.Context) {
|
||||||
// Bind the response (context) with the loginRequest struct
|
// Bind the response (context) with the loginRequest struct
|
||||||
var credentials loginRequest
|
var credentials loginRequest
|
||||||
if err := c.ShouldBindJSON(&credentials); err != nil {
|
if err := c.ShouldBindJSON(&credentials); err != nil {
|
||||||
helper.UnprocessableEntityError(c, err.Error())
|
helper.UnauthorizedError(c, "Wrong username or password")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the login request
|
// Validate the login request
|
||||||
if errs := credentials.validate(); errs != nil {
|
if errs := credentials.validate(); errs != nil {
|
||||||
helper.BadRequestError(c, errs.Error())
|
helper.UnauthorizedError(c, "Wrong username or password")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,14 +48,14 @@ func authenticate(c *gin.Context) {
|
||||||
var user User
|
var user User
|
||||||
err := user.ByUsername(credentials.Username)
|
err := user.ByUsername(credentials.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.NotFoundError(c, "User not found")
|
helper.UnauthorizedError(c, "Wrong username or password")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the password
|
// Validate the password
|
||||||
err = user.validatePassword(credentials.Password)
|
err = user.validatePassword(credentials.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.UnauthorizedError(c, "Invalid password")
|
helper.UnauthorizedError(c, "Wrong username or password")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/helper"
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/helper"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -47,11 +46,10 @@ func getUsers(c *gin.Context) {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
var users []database.User
|
var users []database.User
|
||||||
err = db.Order("ID asc").Find(&users).Error
|
err = db.Order("ID asc").Find(&users).Error
|
||||||
if helper.DBError(c, err) {
|
if !helper.DBError(c, err) {
|
||||||
return
|
c.JSON(http.StatusOK, gin.H{"users": users})
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"users": users})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUser godoc
|
// AddUser godoc
|
||||||
|
@ -83,7 +81,7 @@ func addUser(c *gin.Context) {
|
||||||
|
|
||||||
// Validate the request
|
// Validate the request
|
||||||
if err = req.validate(); err != nil {
|
if err = req.validate(); err != nil {
|
||||||
helper.UnprocessableEntityError(c, err.Error())
|
helper.BadRequestError(c, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,18 +98,16 @@ func addUser(c *gin.Context) {
|
||||||
// Hash the password before saving it to the DB
|
// Hash the password before saving it to the DB
|
||||||
err = newUser.setPassword(newUser.Password)
|
err = newUser.setPassword(newUser.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.UnprocessableEntityError(c, "Unable to encrypt the password")
|
helper.InternalServerError(c, "Unable to encrypt the password")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the user in the DB
|
// Save the user in the DB
|
||||||
err = newUser.save()
|
err = newUser.save()
|
||||||
if err != nil {
|
if !helper.DBError(c, err) {
|
||||||
helper.DBError(c, err)
|
c.JSON(http.StatusOK, gin.H{"user": newUser.User})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"user": newUser.User})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUser godoc
|
// UpdateUser godoc
|
||||||
|
@ -131,24 +127,16 @@ func addUser(c *gin.Context) {
|
||||||
// @Router /users/{userID} [put]
|
// @Router /users/{userID} [put]
|
||||||
func updateUser(c *gin.Context) {
|
func updateUser(c *gin.Context) {
|
||||||
|
|
||||||
err := database.ValidateRole(c, database.ModelUser, database.Update)
|
// no need to validate the role since updating a single user is role independent
|
||||||
if err != nil {
|
//err := database.ValidateRole(c, database.ModelUser, database.Update)
|
||||||
helper.UnprocessableEntityError(c, err.Error())
|
//if err != nil {
|
||||||
return
|
// helper.UnprocessableEntityError(c, err.Error())
|
||||||
}
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
// Get the user's (to be updated) ID from the context
|
// Get the user's (to be updated) ID from the context
|
||||||
var oldUser User
|
toBeUpdatedID, err := helper.GetIDOfElement(c, "userID", "path", -1)
|
||||||
toBeUpdatedID, err := strconv.Atoi(c.Param("userID"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.NotFoundError(c, fmt.Sprintf("Could not get user's ID from context"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the user
|
|
||||||
err = oldUser.ByID(uint(toBeUpdatedID))
|
|
||||||
if err != nil {
|
|
||||||
helper.DBError(c, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,18 +150,10 @@ func updateUser(c *gin.Context) {
|
||||||
// except Role
|
// except Role
|
||||||
|
|
||||||
// Get caller's ID from context
|
// Get caller's ID from context
|
||||||
callerID, exists := c.Get(database.UserIDCtx)
|
callerID, _ := c.Get(database.UserIDCtx)
|
||||||
if !exists {
|
|
||||||
helper.NotFoundError(c, fmt.Sprintf("Could not get caller's ID from context"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get caller's Role from context
|
// Get caller's Role from context
|
||||||
callerRole, exists := c.Get(database.UserRoleCtx)
|
callerRole, _ := c.Get(database.UserRoleCtx)
|
||||||
if !exists {
|
|
||||||
helper.NotFoundError(c, fmt.Sprintf("Could not get caller's Role from context"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if uint(toBeUpdatedID) != callerID && callerRole != "Admin" {
|
if uint(toBeUpdatedID) != callerID && callerRole != "Admin" {
|
||||||
helper.ForbiddenError(c, "Invalid authorization")
|
helper.ForbiddenError(c, "Invalid authorization")
|
||||||
|
@ -183,7 +163,7 @@ func updateUser(c *gin.Context) {
|
||||||
// Bind the (context) with the updateUserRequest struct
|
// Bind the (context) with the updateUserRequest struct
|
||||||
var req updateUserRequest
|
var req updateUserRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.UnprocessableEntityError(c, fmt.Sprintf("%v", err))
|
helper.BadRequestError(c, fmt.Sprintf("%v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,27 +173,33 @@ func updateUser(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the user
|
||||||
|
var oldUser User
|
||||||
|
err = oldUser.ByID(uint(toBeUpdatedID))
|
||||||
|
if helper.DBError(c, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Create the updatedUser from oldUser considering callerRole (in
|
// Create the updatedUser from oldUser considering callerRole (in
|
||||||
// case that the request updates the role of the old user)
|
// case that the request updates the role of the old user)
|
||||||
updatedUser, err := req.updatedUser(callerRole, oldUser)
|
updatedUser, err := req.updatedUser(callerRole, oldUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "Admin") {
|
if strings.Contains(err.Error(), "Admin") {
|
||||||
helper.ForbiddenError(c, err.Error())
|
helper.ForbiddenError(c, err.Error())
|
||||||
|
} else if strings.Contains(err.Error(), "Username") {
|
||||||
} else if strings.Contains(err.Error(), "Username") || strings.Contains(err.Error(), "password") {
|
|
||||||
helper.BadRequestError(c, err.Error())
|
helper.BadRequestError(c, err.Error())
|
||||||
|
} else { // password encryption failed
|
||||||
|
helper.InternalServerError(c, err.Error())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally update the user
|
// Finally update the user
|
||||||
err = oldUser.update(updatedUser)
|
err = oldUser.update(updatedUser)
|
||||||
if err != nil {
|
if !helper.DBError(c, err) {
|
||||||
helper.DBError(c, err)
|
c.JSON(http.StatusOK, gin.H{"user": updatedUser.User})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"user": updatedUser.User})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUser godoc
|
// GetUser godoc
|
||||||
|
@ -230,15 +216,15 @@ func updateUser(c *gin.Context) {
|
||||||
// @Router /users/{userID} [get]
|
// @Router /users/{userID} [get]
|
||||||
func getUser(c *gin.Context) {
|
func getUser(c *gin.Context) {
|
||||||
|
|
||||||
err := database.ValidateRole(c, database.ModelUser, database.Read)
|
// role validation not needed because updating a single user is role-independent
|
||||||
if err != nil {
|
//err := database.ValidateRole(c, database.ModelUser, database.Read)
|
||||||
helper.UnprocessableEntityError(c, err.Error())
|
//if err != nil {
|
||||||
return
|
// helper.UnprocessableEntityError(c, err.Error())
|
||||||
}
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
id, err := strconv.Atoi(c.Param("userID"))
|
id, err := helper.GetIDOfElement(c, "userID", "path", -1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.NotFoundError(c, fmt.Sprintf("Could not get user's ID from context"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,12 +238,10 @@ func getUser(c *gin.Context) {
|
||||||
|
|
||||||
var user User
|
var user User
|
||||||
err = user.ByID(uint(id))
|
err = user.ByID(uint(id))
|
||||||
if err != nil {
|
if !helper.DBError(c, err) {
|
||||||
helper.DBError(c, err)
|
c.JSON(http.StatusOK, gin.H{"user": user.User})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"user": user.User})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser godoc
|
// DeleteUser godoc
|
||||||
|
@ -280,25 +264,21 @@ func deleteUser(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var user User
|
var user User
|
||||||
id, err := strconv.Atoi(c.Param("userID"))
|
id, err := helper.GetIDOfElement(c, "userID", "path", -1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.NotFoundError(c, fmt.Sprintf("Could not get user's ID from context"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the user exist
|
// Check that the user exist
|
||||||
err = user.ByID(uint(id))
|
err = user.ByID(uint(id))
|
||||||
if err != nil {
|
if helper.DBError(c, err) {
|
||||||
helper.DBError(c, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to remove user
|
// Try to remove user
|
||||||
err = user.remove()
|
err = user.remove()
|
||||||
if err != nil {
|
if !helper.DBError(c, err) {
|
||||||
helper.DBError(c, err)
|
c.JSON(http.StatusOK, gin.H{"user": user.User})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"user": user.User})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,19 +30,13 @@ func (u *User) remove() error {
|
||||||
func (u *User) ByUsername(username string) error {
|
func (u *User) ByUsername(username string) error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
err := db.Find(u, "Username = ?", username).Error
|
err := db.Find(u, "Username = ?", username).Error
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) ByID(id uint) error {
|
func (u *User) ByID(id uint) error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
err := db.Find(u, id).Error
|
err := db.Find(u, id).Error
|
||||||
if err != nil {
|
return err
|
||||||
return fmt.Errorf("User with id=%v does not exist", id)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) setPassword(password string) error {
|
func (u *User) setPassword(password string) error {
|
||||||
|
|
|
@ -48,30 +48,30 @@ func TestAuthenticate(t *testing.T) {
|
||||||
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
|
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
|
||||||
|
|
||||||
// try to authenticate with non JSON body
|
// try to authenticate with non JSON body
|
||||||
// should result in unprocessable entity
|
// should result in unauthorized
|
||||||
w1 := httptest.NewRecorder()
|
w1 := httptest.NewRecorder()
|
||||||
body, _ := json.Marshal("This is no JSON")
|
body, _ := json.Marshal("This is no JSON")
|
||||||
req, err := http.NewRequest("POST", "/api/authenticate", bytes.NewBuffer(body))
|
req, err := http.NewRequest("POST", "/api/authenticate", bytes.NewBuffer(body))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
router.ServeHTTP(w1, req)
|
router.ServeHTTP(w1, req)
|
||||||
assert.Equalf(t, 422, w1.Code, "Response body: \n%v\n", w1.Body)
|
assert.Equalf(t, 401, w1.Code, "Response body: \n%v\n", w1.Body)
|
||||||
|
|
||||||
malformedCredentials := helper.Credentials{
|
malformedCredentials := helper.Credentials{
|
||||||
Username: "TEST1",
|
Username: "TEST1",
|
||||||
}
|
}
|
||||||
// try to authenticate with non JSON body
|
// try to authenticate with malformed credentials
|
||||||
// should result in bad request
|
// should result in unauthorized
|
||||||
w2 := httptest.NewRecorder()
|
w2 := httptest.NewRecorder()
|
||||||
body, _ = json.Marshal(malformedCredentials)
|
body, _ = json.Marshal(malformedCredentials)
|
||||||
req, err = http.NewRequest("POST", "/api/authenticate", bytes.NewBuffer(body))
|
req, err = http.NewRequest("POST", "/api/authenticate", bytes.NewBuffer(body))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
router.ServeHTTP(w2, req)
|
router.ServeHTTP(w2, req)
|
||||||
assert.Equal(t, 400, w2.Code, w2.Body)
|
assert.Equal(t, 401, w2.Code, w2.Body)
|
||||||
|
|
||||||
// try to authenticate with a username that does not exist in the DB
|
// try to authenticate with a username that does not exist in the DB
|
||||||
// should result in not found
|
// should result in unauthorized
|
||||||
malformedCredentials.Username = "NOTEXIST"
|
malformedCredentials.Username = "NOTEXIST"
|
||||||
malformedCredentials.Password = "blablabla"
|
malformedCredentials.Password = "blablabla"
|
||||||
w3 := httptest.NewRecorder()
|
w3 := httptest.NewRecorder()
|
||||||
|
@ -80,7 +80,7 @@ func TestAuthenticate(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
router.ServeHTTP(w3, req)
|
router.ServeHTTP(w3, req)
|
||||||
assert.Equal(t, 404, w3.Code, w3.Body)
|
assert.Equal(t, 401, w3.Code, w3.Body)
|
||||||
|
|
||||||
// try to authenticate with a correct user name and a wrong password
|
// try to authenticate with a correct user name and a wrong password
|
||||||
// should result in unauthorized
|
// should result in unauthorized
|
||||||
|
@ -94,6 +94,11 @@ func TestAuthenticate(t *testing.T) {
|
||||||
router.ServeHTTP(w4, req)
|
router.ServeHTTP(w4, req)
|
||||||
assert.Equal(t, 401, w4.Code, w4.Body)
|
assert.Equal(t, 401, w4.Code, w4.Body)
|
||||||
|
|
||||||
|
// authenticate as admin
|
||||||
|
_, err = helper.AuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", helper.AdminCredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddGetUser(t *testing.T) {
|
func TestAddGetUser(t *testing.T) {
|
||||||
|
@ -107,14 +112,83 @@ func TestAddGetUser(t *testing.T) {
|
||||||
"/api/authenticate", "POST", helper.AdminCredentials)
|
"/api/authenticate", "POST", helper.AdminCredentials)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// test POST user/ $newUser
|
// try to POST with non JSON body
|
||||||
|
// should result in bad request
|
||||||
|
code, resp, err := helper.TestEndpoint(router, token,
|
||||||
|
"/api/users", "POST", "This is not JSON")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
wrongUser := UserRequest{
|
||||||
|
Username: "ab",
|
||||||
|
Password: "123456",
|
||||||
|
Mail: "bla@test.com",
|
||||||
|
Role: "Guest",
|
||||||
|
}
|
||||||
|
// try POST with too short username
|
||||||
|
// should result in bad request
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/users", "POST", helper.KeyModels{"user": wrongUser})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// try POST with too short password
|
||||||
|
// should result in bad request
|
||||||
|
wrongUser.Username = "Longenoughusername"
|
||||||
|
wrongUser.Password = "short"
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/users", "POST", helper.KeyModels{"user": wrongUser})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// try POST with wrong role
|
||||||
|
// should result in bad request
|
||||||
|
wrongUser.Password = "longenough"
|
||||||
|
wrongUser.Role = "ThisIsNotARole"
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/users", "POST", helper.KeyModels{"user": wrongUser})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
//try POST with wrong email
|
||||||
|
// should result in bad request
|
||||||
|
wrongUser.Mail = "noemailaddress"
|
||||||
|
wrongUser.Role = "Guest"
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/users", "POST", helper.KeyModels{"user": wrongUser})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// try POST with missing required fields
|
||||||
|
// should result in bad request
|
||||||
|
wrongUser.Mail = ""
|
||||||
|
wrongUser.Role = ""
|
||||||
|
wrongUser.Password = ""
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/users", "POST", helper.KeyModels{"user": wrongUser})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// try POST with username that is already taken
|
||||||
|
// should result in unprocessable entity
|
||||||
|
wrongUser.Mail = "test@test.com"
|
||||||
|
wrongUser.Role = "Guest"
|
||||||
|
wrongUser.Password = "blablabla"
|
||||||
|
wrongUser.Username = "User_A"
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/users", "POST", helper.KeyModels{"user": wrongUser})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
newUser := UserRequest{
|
newUser := UserRequest{
|
||||||
Username: "Alice483",
|
Username: "Alice483",
|
||||||
Password: "th1s_I5_@lice#",
|
Password: "th1s_I5_@lice#",
|
||||||
Mail: "mail@domain.com",
|
Mail: "mail@domain.com",
|
||||||
Role: "User",
|
Role: "User",
|
||||||
}
|
}
|
||||||
code, resp, err := helper.TestEndpoint(router, token,
|
|
||||||
|
// test POST user/ $newUser
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
"/api/users", "POST", helper.KeyModels{"user": newUser})
|
"/api/users", "POST", helper.KeyModels{"user": newUser})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
@ -142,6 +216,13 @@ func TestAddGetUser(t *testing.T) {
|
||||||
// Compare GET's response with the newUser (Password omitted)
|
// Compare GET's response with the newUser (Password omitted)
|
||||||
err = helper.CompareResponse(resp, helper.KeyModels{"user": newUser})
|
err = helper.CompareResponse(resp, helper.KeyModels{"user": newUser})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// try to GET user with invalid user ID
|
||||||
|
// should result in bad request
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/users/bla"), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUsersNotAllowedActions(t *testing.T) {
|
func TestUsersNotAllowedActions(t *testing.T) {
|
||||||
|
@ -238,6 +319,19 @@ func TestGetAllUsers(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, finalNumber, initialNumber+1)
|
assert.Equal(t, finalNumber, initialNumber+1)
|
||||||
|
|
||||||
|
// authenticate as normal user
|
||||||
|
token, err = helper.AuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", helper.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// try to get all users as normal user
|
||||||
|
// should result in unprocessable entity eror
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/users", "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestModifyAddedUserAsUser(t *testing.T) {
|
func TestModifyAddedUserAsUser(t *testing.T) {
|
||||||
|
@ -274,6 +368,20 @@ func TestModifyAddedUserAsUser(t *testing.T) {
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Try PUT with invalid user ID in path
|
||||||
|
// Should return a bad request
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token, fmt.Sprintf("/api/users/blabla"), "PUT",
|
||||||
|
helper.KeyModels{"user": newUser})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Try to PUT a non JSON body
|
||||||
|
// Should return a bad request
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/users/%v", newUserID), "PUT", "This is no JSON")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
// Turn password member of newUser to empty string so it is omitted
|
// Turn password member of newUser to empty string so it is omitted
|
||||||
// in marshaling. The password will never be included in the
|
// in marshaling. The password will never be included in the
|
||||||
// response and if is non empty in request we will not be able to do
|
// response and if is non empty in request we will not be able to do
|
||||||
|
@ -377,8 +485,27 @@ func TestInvalidUserUpdate(t *testing.T) {
|
||||||
newUserID, err := helper.GetResponseID(resp)
|
newUserID, err := helper.GetResponseID(resp)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// try PUT with userID that does not exist
|
||||||
|
// should result in not found
|
||||||
|
modRequest := UserRequest{Password: "longenough"}
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/users/%v", newUserID+1), "PUT",
|
||||||
|
helper.KeyModels{"user": modRequest})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// try to PUT with username that is already taken
|
||||||
|
// should result in bad request
|
||||||
|
modRequest.Password = ""
|
||||||
|
modRequest.Username = "User_A"
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/users/%v", newUserID), "PUT",
|
||||||
|
helper.KeyModels{"user": modRequest})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
// modify newUser's password with INVALID password
|
// modify newUser's password with INVALID password
|
||||||
modRequest := UserRequest{Password: "short"}
|
modRequest.Password = "short"
|
||||||
code, resp, err = helper.TestEndpoint(router, token,
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/users/%v", newUserID), "PUT",
|
fmt.Sprintf("/api/users/%v", newUserID), "PUT",
|
||||||
helper.KeyModels{"user": modRequest})
|
helper.KeyModels{"user": modRequest})
|
||||||
|
@ -400,6 +527,7 @@ func TestInvalidUserUpdate(t *testing.T) {
|
||||||
helper.KeyModels{"user": modRequest})
|
helper.KeyModels{"user": modRequest})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestModifyAddedUserAsAdmin(t *testing.T) {
|
func TestModifyAddedUserAsAdmin(t *testing.T) {
|
||||||
|
@ -510,6 +638,20 @@ func TestDeleteUser(t *testing.T) {
|
||||||
newUserID, err := helper.GetResponseID(resp)
|
newUserID, err := helper.GetResponseID(resp)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// try to DELETE with invalid ID
|
||||||
|
// should result in bad request
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/users/bla"), "DELETE", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// try to DELETE with ID that does not exist
|
||||||
|
// should result in not found
|
||||||
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/users/%v", newUserID+1), "DELETE", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
// Count the number of all the users returned
|
// Count the number of all the users returned
|
||||||
initialNumber, err := helper.LengthOfResponse(router, token,
|
initialNumber, err := helper.LengthOfResponse(router, token,
|
||||||
"/api/users", "GET", nil)
|
"/api/users", "GET", nil)
|
||||||
|
|
|
@ -10,11 +10,11 @@ var validate *validator.Validate
|
||||||
|
|
||||||
type loginRequest struct {
|
type loginRequest struct {
|
||||||
Username string `form:"Username" validate:"required"`
|
Username string `form:"Username" validate:"required"`
|
||||||
Password string `form:"Password" validate:"required,min=6"`
|
Password string `form:"Password" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type validUpdatedRequest struct {
|
type validUpdatedRequest struct {
|
||||||
Username string `form:"Username" validate:"omitempty"`
|
Username string `form:"Username" validate:"omitempty,min=3"`
|
||||||
Password string `form:"Password" validate:"omitempty,min=6"`
|
Password string `form:"Password" validate:"omitempty,min=6"`
|
||||||
Role string `form:"Role" validate:"omitempty,oneof=Admin User Guest"`
|
Role string `form:"Role" validate:"omitempty,oneof=Admin User Guest"`
|
||||||
Mail string `form:"Mail" validate:"omitempty,email"`
|
Mail string `form:"Mail" validate:"omitempty,email"`
|
||||||
|
@ -25,7 +25,7 @@ type updateUserRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type validNewUser struct {
|
type validNewUser struct {
|
||||||
Username string `form:"Username" validate:"required"`
|
Username string `form:"Username" validate:"required,min=3"`
|
||||||
Password string `form:"Password" validate:"required,min=6"`
|
Password string `form:"Password" validate:"required,min=6"`
|
||||||
Role string `form:"Role" validate:"required,oneof=Admin User Guest"`
|
Role string `form:"Role" validate:"required,oneof=Admin User Guest"`
|
||||||
Mail string `form:"Mail" validate:"required,email"`
|
Mail string `form:"Mail" validate:"required,email"`
|
||||||
|
@ -63,7 +63,8 @@ func (r *updateUserRequest) updatedUser(role interface{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the username making sure is NOT taken
|
// Update the username making sure is NOT taken
|
||||||
if err := u.ByUsername(r.Username); err == nil {
|
var testUser User
|
||||||
|
if err := testUser.ByUsername(r.Username); err == nil {
|
||||||
return u, fmt.Errorf("Username is alreaday taken")
|
return u, fmt.Errorf("Username is alreaday taken")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue