Validation
Some checks failed
release-nightly / build-docker (push) Has been cancelled

This commit is contained in:
LittleSheep 2024-10-20 21:22:53 +08:00
parent a563c8f5bc
commit 799bfcc263
5 changed files with 65 additions and 27 deletions

View File

@ -19,8 +19,8 @@ func NewServer() *HTTPApp {
app := fiber.New(fiber.Config{ app := fiber.New(fiber.Config{
DisableStartupMessage: true, DisableStartupMessage: true,
EnableIPValidation: true, EnableIPValidation: true,
ServerHeader: "Hydrogen.Nexus", ServerHeader: "Hypernet.Nexus",
AppName: "Hydrogen.Nexus", AppName: "Hypernet.Nexus",
ProxyHeader: fiber.HeaderXForwardedFor, ProxyHeader: fiber.HeaderXForwardedFor,
JSONEncoder: json.Marshal, JSONEncoder: json.Marshal,
JSONDecoder: json.Unmarshal, JSONDecoder: json.Unmarshal,

View File

@ -1,7 +1,9 @@
package nex package nex
import ( import (
"fmt"
"github.com/goccy/go-json" "github.com/goccy/go-json"
"net/http"
"sync" "sync"
) )
@ -15,6 +17,28 @@ type CommandCtx struct {
values sync.Map values sync.Map
} }
func CtxValueMustBe[T any](c *CommandCtx, key string) (T, error) {
if val, ok := c.values.Load(key); ok {
if v, ok := val.(T); ok {
return v, nil
}
}
var out T
if err := c.Write([]byte(fmt.Sprintf("value %s not found in type %T", key, out)), "text/plain+error", http.StatusBadRequest); err != nil {
return out, err
}
return out, fmt.Errorf("value %s not found", key)
}
func CtxValueShouldBe[T any](c *CommandCtx, key string, defaultValue T) T {
if val, ok := c.values.Load(key); ok {
if v, ok := val.(T); ok {
return v
}
}
return defaultValue
}
func (c *CommandCtx) Values() map[string]any { func (c *CommandCtx) Values() map[string]any {
duplicate := make(map[string]any) duplicate := make(map[string]any)
c.values.Range(func(key, value any) bool { c.values.Range(func(key, value any) bool {

View File

@ -1,8 +0,0 @@
package nex
const (
ServiceTypeAuthProvider = "auth"
ServiceTypeFileProvider = "files"
ServiceTypeInteractiveProvider = "interactive"
ServiceTypeMessagingProvider = "messaging"
)

View File

@ -1,7 +1,10 @@
package cruda package cruda
import ( import (
"errors"
"git.solsynth.dev/hypernet/nexus/pkg/nex" "git.solsynth.dev/hypernet/nexus/pkg/nex"
"github.com/go-playground/validator/v10"
"gorm.io/gorm"
"net/http" "net/http"
) )
@ -9,7 +12,7 @@ type CrudAction func(v *CrudConn) nex.CommandHandler
func AddModel[T any](v *CrudConn, model T, id, prefix string, tags []string) error { func AddModel[T any](v *CrudConn, model T, id, prefix string, tags []string) error {
funcList := []CrudAction{cmdList[T], cmdGet[T], cmdCreate[T], cmdUpdate[T], cmdDelete[T]} funcList := []CrudAction{cmdList[T], cmdGet[T], cmdCreate[T], cmdUpdate[T], cmdDelete[T]}
funcCmds := []string{".list", ".get", ".create", ".update", ".delete"} funcCmds := []string{".list", "", "", "", ""}
funcMethods := []string{"get", "get", "put", "patch", "delete"} funcMethods := []string{"get", "get", "put", "patch", "delete"}
for idx, fn := range funcList { for idx, fn := range funcList {
if err := v.Conn.AddCommand(prefix+id+funcCmds[idx], funcMethods[idx], tags, fn(v)); err != nil { if err := v.Conn.AddCommand(prefix+id+funcCmds[idx], funcMethods[idx], tags, fn(v)); err != nil {
@ -19,10 +22,12 @@ func AddModel[T any](v *CrudConn, model T, id, prefix string, tags []string) err
return nil return nil
} }
var validate = validator.New(validator.WithRequiredStructEnabled())
func cmdList[T any](c *CrudConn) nex.CommandHandler { func cmdList[T any](c *CrudConn) nex.CommandHandler {
return func(ctx *nex.CommandCtx) error { return func(ctx *nex.CommandCtx) error {
take := int(ctx.ValueOrElse("query.take", 10).(int64)) take := int(nex.CtxValueShouldBe[int64](ctx, "query.take", 10))
skip := int(ctx.ValueOrElse("query.skip", 0).(int64)) skip := int(nex.CtxValueShouldBe[int64](ctx, "query.skip", 0))
var str T var str T
var count int64 var count int64
@ -44,10 +49,16 @@ func cmdList[T any](c *CrudConn) nex.CommandHandler {
func cmdGet[T any](c *CrudConn) nex.CommandHandler { func cmdGet[T any](c *CrudConn) nex.CommandHandler {
return func(ctx *nex.CommandCtx) error { return func(ctx *nex.CommandCtx) error {
id := ctx.ValueOrElse("query.id", 0).(int64) id, err := nex.CtxValueMustBe[int64](ctx, "query.id")
if err != nil {
return err
}
var out T var out T
if err := c.db.First(&out, "id = ?", id).Error; err != nil { if err := c.db.First(&out, "id = ?", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ctx.Write([]byte(err.Error()), "text/plain", http.StatusNotFound)
}
return err return err
} }
@ -57,29 +68,34 @@ func cmdGet[T any](c *CrudConn) nex.CommandHandler {
func cmdCreate[T any](c *CrudConn) nex.CommandHandler { func cmdCreate[T any](c *CrudConn) nex.CommandHandler {
return func(ctx *nex.CommandCtx) error { return func(ctx *nex.CommandCtx) error {
var out T var payload T
if err := ctx.ReadJSON(&out); err != nil { if err := ctx.ReadJSON(&payload); err != nil {
return err return err
} else if err := validate.Struct(payload); err != nil {
return ctx.Write([]byte(err.Error()), "text/plain+error", http.StatusBadRequest)
} }
// TODO validation
if err := c.db.Create(&out).Error; err != nil { if err := c.db.Create(&payload).Error; err != nil {
return err return err
} }
return ctx.JSON(out, http.StatusOK) return ctx.JSON(payload, http.StatusOK)
} }
} }
func cmdUpdate[T any](c *CrudConn) nex.CommandHandler { func cmdUpdate[T any](c *CrudConn) nex.CommandHandler {
return func(ctx *nex.CommandCtx) error { return func(ctx *nex.CommandCtx) error {
id := ctx.ValueOrElse("query.id", 0).(int64) id, err := nex.CtxValueMustBe[int64](ctx, "query.id")
if err != nil {
return err
}
var payload T var payload T
if err := ctx.ReadJSON(&payload); err != nil { if err := ctx.ReadJSON(&payload); err != nil {
return err return err
} else if err := validate.Struct(payload); err != nil {
return ctx.Write([]byte(err.Error()), "text/plain+error", http.StatusBadRequest)
} }
// TODO validation
var out T var out T
if err := c.db.Model(out).Where("id = ?", id).Updates(&payload).Error; err != nil { if err := c.db.Model(out).Where("id = ?", id).Updates(&payload).Error; err != nil {
@ -96,13 +112,19 @@ func cmdUpdate[T any](c *CrudConn) nex.CommandHandler {
func cmdDelete[T any](c *CrudConn) nex.CommandHandler { func cmdDelete[T any](c *CrudConn) nex.CommandHandler {
return func(ctx *nex.CommandCtx) error { return func(ctx *nex.CommandCtx) error {
id := ctx.ValueOrElse("query.id", 0).(int64) id, err := nex.CtxValueMustBe[int64](ctx, "query.id")
if err != nil {
var out T
if err := c.db.Delete(&out, "id = ?", id).Error; err != nil {
return err return err
} }
return ctx.JSON(out, http.StatusOK) var out T
if err := c.db.Delete(&out, "id = ?", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ctx.Write([]byte(err.Error()), "text/plain", http.StatusNotFound)
}
return err
}
return ctx.Write(nil, "text/plain", http.StatusOK)
} }
} }

View File

@ -11,7 +11,7 @@ import (
type Test struct { type Test struct {
cruda.BaseModel cruda.BaseModel
Content string `json:"content"` Content string `json:"content" validate:"required"`
} }
func TestCrudaCommand(t *testing.T) { func TestCrudaCommand(t *testing.T) {