mirror of
https://github.com/pushbits/server.git
synced 2025-06-06 12:41:59 +02:00
Introduce middleware for parsing ID from URI
This commit is contained in:
parent
e1cd2d2f8e
commit
018ce2e537
8 changed files with 74 additions and 50 deletions
|
@ -40,7 +40,7 @@ func (h *ApplicationHandler) applicationExists(token string) bool {
|
||||||
func (h *ApplicationHandler) CreateApplication(ctx *gin.Context) {
|
func (h *ApplicationHandler) CreateApplication(ctx *gin.Context) {
|
||||||
var createApplication model.CreateApplication
|
var createApplication model.CreateApplication
|
||||||
|
|
||||||
if success := successOrAbort(ctx, http.StatusBadRequest, ctx.Bind(&createApplication)); !success {
|
if err := ctx.Bind(&createApplication); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,13 +69,12 @@ 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) {
|
||||||
var deleteApplication model.DeleteApplication
|
id, err := getID(ctx)
|
||||||
|
if err != nil {
|
||||||
if success := successOrAbort(ctx, http.StatusBadRequest, ctx.BindUri(&deleteApplication)); !success {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
application, err := h.DB.GetApplicationByID(deleteApplication.ID)
|
application, err := h.DB.GetApplicationByID(id)
|
||||||
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
|
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -99,13 +98,12 @@ 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) {
|
||||||
var updateApplication model.UpdateApplication
|
id, err := getID(ctx)
|
||||||
|
if err != nil {
|
||||||
if success := successOrAbort(ctx, http.StatusBadRequest, ctx.BindUri(&updateApplication)); !success {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
application, err := h.DB.GetApplicationByID(updateApplication.ID)
|
application, err := h.DB.GetApplicationByID(id)
|
||||||
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
|
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -114,6 +112,12 @@ func (h *ApplicationHandler) UpdateApplication(ctx *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var updateApplication model.UpdateApplication
|
||||||
|
|
||||||
|
if err := ctx.BindUri(&updateApplication); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("Updating application %s.\n", application.Name)
|
log.Printf("Updating application %s.\n", application.Name)
|
||||||
|
|
||||||
// TODO: Handle unbound members.
|
// TODO: Handle unbound members.
|
||||||
|
|
36
api/middleware.go
Normal file
36
api/middleware.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type idInURI struct {
|
||||||
|
ID uint `uri:"id" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireIDInURI returns a Gin middleware which requires an ID to be supplied in the URI of the request.
|
||||||
|
func RequireIDInURI() gin.HandlerFunc {
|
||||||
|
return func(ctx *gin.Context) {
|
||||||
|
var requestModel idInURI
|
||||||
|
|
||||||
|
if err := ctx.BindUri(&requestModel); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ type NotificationHandler struct {
|
||||||
func (h *NotificationHandler) CreateNotification(ctx *gin.Context) {
|
func (h *NotificationHandler) CreateNotification(ctx *gin.Context) {
|
||||||
var notification model.Notification
|
var notification model.Notification
|
||||||
|
|
||||||
if success := successOrAbort(ctx, http.StatusBadRequest, ctx.Bind(¬ification)); !success {
|
if err := ctx.Bind(¬ification); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
api/user.go
26
api/user.go
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
// The UserDatabase interface for encapsulating database access.
|
// The UserDatabase interface for encapsulating database access.
|
||||||
type UserDatabase interface {
|
type UserDatabase interface {
|
||||||
CreateUser(user model.ExternalUserWithCredentials) (*model.User, error)
|
CreateUser(user model.CreateUser) (*model.User, error)
|
||||||
DeleteUser(user *model.User) error
|
DeleteUser(user *model.User) error
|
||||||
UpdateUser(user *model.User) error
|
UpdateUser(user *model.User) error
|
||||||
GetUserByID(ID uint) (*model.User, error)
|
GetUserByID(ID uint) (*model.User, error)
|
||||||
|
@ -57,9 +57,9 @@ func (h *UserHandler) ensureIsNotLastAdmin(ctx *gin.Context) (int, error) {
|
||||||
// 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.ExternalUserWithCredentials
|
var externalUser model.CreateUser
|
||||||
|
|
||||||
if success := successOrAbort(ctx, http.StatusBadRequest, ctx.Bind(&externalUser)); !success {
|
if err := ctx.Bind(&externalUser); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,13 +81,12 @@ 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) {
|
||||||
var deleteUser model.DeleteUser
|
id, err := getID(ctx)
|
||||||
|
if err != nil {
|
||||||
if success := successOrAbort(ctx, http.StatusBadRequest, ctx.BindUri(&deleteUser)); !success {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.DB.GetUserByID(deleteUser.ID)
|
user, err := h.DB.GetUserByID(id)
|
||||||
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
|
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -125,17 +124,22 @@ 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) {
|
||||||
var updateUser model.UpdateUser
|
id, err := getID(ctx)
|
||||||
|
if err != nil {
|
||||||
if success := successOrAbort(ctx, http.StatusBadRequest, ctx.BindUri(&updateUser)); !success {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.DB.GetUserByID(updateUser.ID)
|
user, err := h.DB.GetUserByID(id)
|
||||||
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
|
if success := successOrAbort(ctx, http.StatusNotFound, err); !success {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var updateUser model.UpdateUser
|
||||||
|
|
||||||
|
if err := ctx.BindUri(&updateUser); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
currentUser := authentication.GetUser(ctx)
|
currentUser := authentication.GetUser(ctx)
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateUser creates a user.
|
// CreateUser creates a user.
|
||||||
func (d *Database) CreateUser(externalUser model.ExternalUserWithCredentials) (*model.User, error) {
|
func (d *Database) CreateUser(externalUser model.CreateUser) (*model.User, error) {
|
||||||
user := externalUser.IntoInternalUser(d.credentialsManager)
|
user := externalUser.IntoInternalUser(d.credentialsManager)
|
||||||
|
|
||||||
return user, d.gormdb.Create(user).Error
|
return user, d.gormdb.Create(user).Error
|
||||||
|
|
|
@ -14,17 +14,7 @@ type CreateApplication struct {
|
||||||
Name string `form:"name" query:"name" json:"name" binding:"required"`
|
Name string `form:"name" query:"name" json:"name" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type applicationIdentification struct {
|
|
||||||
ID uint `uri:"id" binding:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteApplication is used to process queries for deleting applications.
|
|
||||||
type DeleteApplication struct {
|
|
||||||
applicationIdentification
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateApplication is used to process queries for updating applications.
|
// UpdateApplication is used to process queries for updating applications.
|
||||||
type UpdateApplication struct {
|
type UpdateApplication struct {
|
||||||
applicationIdentification
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ type UserCredentials struct {
|
||||||
Password string `json:"password,omitempty" form:"password" query:"password" binding:"required"`
|
Password string `json:"password,omitempty" form:"password" query:"password" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExternalUserWithCredentials represents a user for external purposes and includes the user's credentials in plaintext.
|
// CreateUser is used to process queries for creating users.
|
||||||
type ExternalUserWithCredentials struct {
|
type CreateUser struct {
|
||||||
ExternalUser
|
ExternalUser
|
||||||
UserCredentials
|
UserCredentials
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,8 @@ func NewUser(cm *credentials.Manager, name, password string, isAdmin bool, matri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntoInternalUser converts a ExternalUserWithCredentials into a User.
|
// IntoInternalUser converts a CreateUser into a User.
|
||||||
func (u *ExternalUserWithCredentials) IntoInternalUser(cm *credentials.Manager) *User {
|
func (u *CreateUser) IntoInternalUser(cm *credentials.Manager) *User {
|
||||||
return &User{
|
return &User{
|
||||||
Name: u.Name,
|
Name: u.Name,
|
||||||
PasswordHash: cm.CreatePasswordHash(u.Password),
|
PasswordHash: cm.CreatePasswordHash(u.Password),
|
||||||
|
@ -67,18 +67,8 @@ func (u *User) IntoExternalUser() *ExternalUser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type userIdentification struct {
|
|
||||||
ID uint `uri:"id" binding:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteUser is used to process queries for deleting users.
|
|
||||||
type DeleteUser struct {
|
|
||||||
userIdentification
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateUser is used to process queries for updating users.
|
// UpdateUser is used to process queries for updating users.
|
||||||
type UpdateUser struct {
|
type UpdateUser struct {
|
||||||
userIdentification
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
IsAdmin bool `json:"is_admin"`
|
IsAdmin bool `json:"is_admin"`
|
||||||
|
|
|
@ -35,8 +35,8 @@ func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *disp
|
||||||
applicationGroup.Use(auth.RequireUser())
|
applicationGroup.Use(auth.RequireUser())
|
||||||
{
|
{
|
||||||
applicationGroup.POST("", applicationHandler.CreateApplication)
|
applicationGroup.POST("", applicationHandler.CreateApplication)
|
||||||
applicationGroup.DELETE("/:id", applicationHandler.DeleteApplication)
|
applicationGroup.DELETE("/:id", api.RequireIDInURI(), applicationHandler.DeleteApplication)
|
||||||
applicationGroup.PUT("/:id", applicationHandler.UpdateApplication)
|
applicationGroup.PUT("/:id", api.RequireIDInURI(), applicationHandler.UpdateApplication)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.POST("/message", auth.RequireApplicationToken(), notificationHandler.CreateNotification)
|
r.POST("/message", auth.RequireApplicationToken(), notificationHandler.CreateNotification)
|
||||||
|
@ -45,8 +45,8 @@ func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *disp
|
||||||
userGroup.Use(auth.RequireAdmin())
|
userGroup.Use(auth.RequireAdmin())
|
||||||
{
|
{
|
||||||
userGroup.POST("", userHandler.CreateUser)
|
userGroup.POST("", userHandler.CreateUser)
|
||||||
userGroup.DELETE("/:id", userHandler.DeleteUser)
|
userGroup.DELETE("/:id", api.RequireIDInURI(), userHandler.DeleteUser)
|
||||||
userGroup.PUT("/:id", userHandler.UpdateUser)
|
userGroup.PUT("/:id", api.RequireIDInURI(), userHandler.UpdateUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue