Remove some duplication in API handlers

This commit is contained in:
eikendev 2020-08-02 17:31:41 +02:00
parent 018ce2e537
commit a5418d9698
No known key found for this signature in database
GPG key ID: A1BDB1B28C8EF694
5 changed files with 66 additions and 54 deletions

View file

@ -36,6 +36,20 @@ func (h *ApplicationHandler) applicationExists(token string) bool {
return application != nil return application != nil
} }
func (h *ApplicationHandler) getApplication(ctx *gin.Context) (*model.Application, error) {
id, err := getID(ctx)
if err != nil {
return nil, err
}
application, err := h.DB.GetApplicationByID(id)
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
return nil, err
}
return application, nil
}
// CreateApplication creates an application. // CreateApplication creates an application.
func (h *ApplicationHandler) CreateApplication(ctx *gin.Context) { func (h *ApplicationHandler) CreateApplication(ctx *gin.Context) {
var createApplication model.CreateApplication var createApplication model.CreateApplication
@ -69,16 +83,11 @@ func (h *ApplicationHandler) CreateApplication(ctx *gin.Context) {
// DeleteApplication deletes an application with a certain ID. // DeleteApplication deletes an application with a certain ID.
func (h *ApplicationHandler) DeleteApplication(ctx *gin.Context) { func (h *ApplicationHandler) DeleteApplication(ctx *gin.Context) {
id, err := getID(ctx) application, err := h.getApplication(ctx)
if err != nil { if err != nil {
return return
} }
application, err := h.DB.GetApplicationByID(id)
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
return
}
if !isCurrentUser(ctx, application.UserID) { if !isCurrentUser(ctx, application.UserID) {
return return
} }
@ -98,22 +107,16 @@ func (h *ApplicationHandler) DeleteApplication(ctx *gin.Context) {
// UpdateApplication updates an application with a certain ID. // UpdateApplication updates an application with a certain ID.
func (h *ApplicationHandler) UpdateApplication(ctx *gin.Context) { func (h *ApplicationHandler) UpdateApplication(ctx *gin.Context) {
id, err := getID(ctx) application, err := h.getApplication(ctx)
if err != nil { if err != nil {
return return
} }
application, err := h.DB.GetApplicationByID(id)
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
return
}
if !isCurrentUser(ctx, application.UserID) { if !isCurrentUser(ctx, application.UserID) {
return return
} }
var updateApplication model.UpdateApplication var updateApplication model.UpdateApplication
if err := ctx.BindUri(&updateApplication); err != nil { if err := ctx.BindUri(&updateApplication); err != nil {
return return
} }

19
api/context.go Normal file
View file

@ -0,0 +1,19 @@
package api
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
)
func getID(ctx *gin.Context) (uint, error) {
id, ok := ctx.MustGet("user").(uint)
if !ok {
err := errors.New("an error occured while retrieving ID from context")
ctx.AbortWithError(http.StatusInternalServerError, err)
return 0, err
}
return id, nil
}

View file

@ -1,9 +1,6 @@
package api package api
import ( import (
"errors"
"net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -23,14 +20,3 @@ func RequireIDInURI() gin.HandlerFunc {
ctx.Set("id", requestModel.ID) ctx.Set("id", requestModel.ID)
} }
} }
func getID(ctx *gin.Context) (uint, error) {
id, ok := ctx.MustGet("user").(uint)
if !ok {
err := errors.New("an error occured while retrieving ID from context")
ctx.AbortWithError(http.StatusInternalServerError, err)
return 0, err
}
return id, nil
}

View file

@ -44,31 +44,48 @@ func (h *UserHandler) userExists(name string) bool {
return user != nil return user != nil
} }
func (h *UserHandler) ensureIsNotLastAdmin(ctx *gin.Context) (int, error) { func (h *UserHandler) requireMultipleAdmins(ctx *gin.Context) error {
if count, err := h.DB.AdminUserCount(); err != nil { if count, err := h.DB.AdminUserCount(); err != nil {
return http.StatusInternalServerError, err ctx.AbortWithError(http.StatusInternalServerError, err)
return err
} else if count == 1 { } else if count == 1 {
return http.StatusBadRequest, errors.New("instance needs at least one privileged user") err := errors.New("instance needs at least one privileged user")
ctx.AbortWithError(http.StatusBadRequest, err)
return err
} }
return 0, nil return nil
}
func (h *UserHandler) getUser(ctx *gin.Context) (*model.User, error) {
id, err := getID(ctx)
if err != nil {
return nil, err
}
application, err := h.DB.GetUserByID(id)
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
return nil, err
}
return application, nil
} }
// CreateUser creates a new user. // CreateUser creates a new user.
// This method assumes that the requesting user has privileges. // This method assumes that the requesting user has privileges.
func (h *UserHandler) CreateUser(ctx *gin.Context) { func (h *UserHandler) CreateUser(ctx *gin.Context) {
var externalUser model.CreateUser var createUser model.CreateUser
if err := ctx.Bind(&externalUser); err != nil { if err := ctx.Bind(&createUser); err != nil {
return return
} }
if h.userExists(externalUser.Name) { if h.userExists(createUser.Name) {
ctx.AbortWithError(http.StatusBadRequest, errors.New("username already exists")) ctx.AbortWithError(http.StatusBadRequest, errors.New("username already exists"))
return return
} }
user, err := h.DB.CreateUser(externalUser) user, err := h.DB.CreateUser(createUser)
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success { if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
return return
@ -81,20 +98,14 @@ func (h *UserHandler) CreateUser(ctx *gin.Context) {
// //
// This method assumes that the requesting user has privileges. // This method assumes that the requesting user has privileges.
func (h *UserHandler) DeleteUser(ctx *gin.Context) { func (h *UserHandler) DeleteUser(ctx *gin.Context) {
id, err := getID(ctx) user, err := h.getUser(ctx)
if err != nil { if err != nil {
return return
} }
user, err := h.DB.GetUserByID(id)
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
return
}
// Last privileged user must not be deleted. // Last privileged user must not be deleted.
if user.IsAdmin { if user.IsAdmin {
if status, err := h.ensureIsNotLastAdmin(ctx); err != nil { if err := h.requireMultipleAdmins(ctx); err != nil {
ctx.AbortWithError(status, err)
return return
} }
} }
@ -124,18 +135,12 @@ func (h *UserHandler) DeleteUser(ctx *gin.Context) {
// This method assumes that the requesting user has privileges. If users can later update their own user, make sure they // This method assumes that the requesting user has privileges. If users can later update their own user, make sure they
// cannot give themselves privileges. // cannot give themselves privileges.
func (h *UserHandler) UpdateUser(ctx *gin.Context) { func (h *UserHandler) UpdateUser(ctx *gin.Context) {
id, err := getID(ctx) user, err := h.getUser(ctx)
if err != nil { if err != nil {
return return
} }
user, err := h.DB.GetUserByID(id)
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
return
}
var updateUser model.UpdateUser var updateUser model.UpdateUser
if err := ctx.BindUri(&updateUser); err != nil { if err := ctx.BindUri(&updateUser); err != nil {
return return
} }
@ -144,8 +149,7 @@ func (h *UserHandler) UpdateUser(ctx *gin.Context) {
// Last privileged user must not be taken privileges. Assumes that the current user has privileges. // Last privileged user must not be taken privileges. Assumes that the current user has privileges.
if user.ID == currentUser.ID && !updateUser.IsAdmin { if user.ID == currentUser.ID && !updateUser.IsAdmin {
if status, err := h.ensureIsNotLastAdmin(ctx); err != nil { if err := h.requireMultipleAdmins(ctx); err != nil {
ctx.AbortWithError(status, err)
return return
} }
} }

View file

@ -10,8 +10,8 @@ import (
) )
// CreateUser creates a user. // CreateUser creates a user.
func (d *Database) CreateUser(externalUser model.CreateUser) (*model.User, error) { func (d *Database) CreateUser(createUser model.CreateUser) (*model.User, error) {
user := externalUser.IntoInternalUser(d.credentialsManager) user := createUser.IntoInternalUser(d.credentialsManager)
return user, d.gormdb.Create(user).Error return user, d.gormdb.Create(user).Error
} }