Add generic CRUD interface for UserIdentifiable entities

This commit is contained in:
qowevisa 2024-10-31 11:07:34 +02:00
parent b09e85b4cb
commit 33b5b73ab2

171
handlers/user_scope_CRUD.go Normal file
View File

@ -0,0 +1,171 @@
package handlers
import (
"fmt"
"git.qowevisa.me/Qowevisa/gonuts/db"
"git.qowevisa.me/Qowevisa/gonuts/types"
"github.com/gin-gonic/gin"
)
// GetHandler returns a generic handler for retrieving an entity by ID.
func GetHandler[T db.UserIdentifiable, R any](transform func(inp T) R) gin.HandlerFunc {
return func(c *gin.Context) {
userID, err := GetUserID(c)
if err != nil {
c.JSON(500, types.ErrorResponse{Message: err.Error()})
return
}
id, err := ParseID(c)
if err != nil {
c.JSON(400, types.ErrorResponse{Message: "Invalid request"})
return
}
dbc := db.Connect()
// NOTE: DO NOT fuck with this
// only by pure luck with GORM First function we don't have SEGFAULT
var entity T
if err := dbc.First(&entity, id).Error; err != nil {
c.JSON(400, types.ErrorResponse{Message: err.Error()})
return
}
if entity.GetID() == 0 {
c.JSON(401, types.ErrorResponse{Message: fmt.Sprintf("Entity with %d id was not found", id)})
return
}
if entity.GetUserID() != userID {
c.JSON(403, types.ErrorResponse{Message: fmt.Sprintf("This entity is not yours")})
return
}
ret := transform(entity)
c.JSON(200, ret)
}
}
// CreateHandler returns a generic handler for creating an entity.
func CreateHandler[T db.UserIdentifiable, R any](entity T, applyChanges func(src R, dst T)) gin.HandlerFunc {
return func(c *gin.Context) {
userID, err := GetUserID(c)
if err != nil {
c.JSON(500, types.ErrorResponse{Message: err.Error()})
return
}
var updates R
if err := c.ShouldBindJSON(&updates); err != nil {
c.JSON(400, types.ErrorResponse{Message: "Invalid request"})
return
}
applyChanges(updates, entity)
entity.SetUserID(userID)
dbc := db.Connect()
if err := dbc.Create(entity).Error; err != nil {
c.JSON(500, types.ErrorResponse{Message: err.Error()})
return
}
c.JSON(200, types.Message{Message: fmt.Sprintf("Entity created with ID %d", entity.GetID())})
}
}
// UpdateHandler returns a generic handler for updating an entity.
func UpdateHandler[T db.UserIdentifiable, R any](
// Filter used to apply only needed changes from srt to dst before updating dst
filter func(src R, dst T),
// Transform used to output only needed fields from inp to response
transform func(inp T) R) gin.HandlerFunc {
return func(c *gin.Context) {
userID, err := GetUserID(c)
if err != nil {
c.JSON(500, types.ErrorResponse{Message: err.Error()})
return
}
id, err := ParseID(c)
if err != nil {
c.JSON(400, types.ErrorResponse{Message: "Invalid request"})
return
}
dbc := db.Connect()
// NOTE: DO NOT fuck with this
// only by pure luck with GORM First function we don't have SEGFAULT
var entity T
if err := dbc.First(&entity, id).Error; err != nil {
c.JSON(400, types.ErrorResponse{Message: err.Error()})
return
}
if entity.GetID() == 0 {
c.JSON(401, types.ErrorResponse{Message: fmt.Sprintf("Entity with %d id was not found", id)})
return
}
if entity.GetUserID() != userID {
c.JSON(403, types.ErrorResponse{Message: fmt.Sprintf("This entity is not yours")})
return
}
var updates R
if err := c.ShouldBindJSON(&updates); err != nil {
c.JSON(400, types.ErrorResponse{Message: "Invalid request"})
return
}
filter(updates, entity)
if err := dbc.Save(&entity).Error; err != nil {
c.JSON(500, types.ErrorResponse{Message: err.Error()})
return
}
ret := transform(entity)
c.JSON(200, ret)
}
}
// DeleteHandler returns a generic handler for deleting an entity by ID.
func DeleteHandler[T db.UserIdentifiable]() gin.HandlerFunc {
return func(c *gin.Context) {
userID, err := GetUserID(c)
if err != nil {
c.JSON(500, types.ErrorResponse{Message: err.Error()})
return
}
id, err := ParseID(c)
if err != nil {
c.JSON(400, types.ErrorResponse{Message: "Invalid request"})
return
}
dbc := db.Connect()
// NOTE: DO NOT fuck with this
// only by pure luck with GORM First function we don't have SEGFAULT
var entity T
if err := dbc.First(&entity, id).Error; err != nil {
c.JSON(400, types.ErrorResponse{Message: err.Error()})
return
}
if entity.GetID() == 0 {
c.JSON(401, types.ErrorResponse{Message: fmt.Sprintf("Entity with %d id was not found", id)})
return
}
if entity.GetUserID() != userID {
c.JSON(403, types.ErrorResponse{Message: fmt.Sprintf("This entity is not yours")})
return
}
if err := dbc.Delete(entity).Error; err != nil {
c.JSON(500, types.ErrorResponse{Message: err.Error()})
return
}
c.JSON(200, types.Message{Message: fmt.Sprintf("Entity with ID %d deleted", entity.GetID())})
}
}