Override ogent code to always return ent errors.

This commit is contained in:
mikestefanello 2025-04-01 19:21:21 -04:00
parent 196d34cc1f
commit 9139942794
6 changed files with 85 additions and 235 deletions

View file

@ -12,13 +12,28 @@ import (
"github.com/ogen-go/ogen"
)
var returnAllErrors = gen.MustParse(gen.NewTemplate("").Parse(`
{{ define "ogent/ogent/helper/error" }}{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{- $pkg := base $.Type.Config.Package }}
if err != nil {
{{- with $.Scope.Tx }}
if rErr := {{ . }}.Rollback(); rErr != nil {
return nil, fmt.Errorf("%w: %v", err, rErr)
}
{{- end }}
// Let the server handle the error.
return nil, err
}
{{ end }}
`))
func main() {
spec := new(ogen.Spec)
oas, err := entoas.NewExtension(entoas.Spec(spec))
if err != nil {
log.Fatalf("creating entoas extension: %v", err)
}
ogent, err := ogent.NewExtension(spec)
ogent, err := ogent.NewExtension(spec, ogent.Templates(returnAllErrors))
if err != nil {
log.Fatalf("creating ogent extension: %v", err)
}

View file

@ -4,7 +4,6 @@ package ogent
import (
"context"
"net/http"
"github.com/go-faster/jx"
"github.com/mikestefanello/pagoda/ent"
@ -38,23 +37,8 @@ func (h *OgentHandler) CreatePasswordToken(ctx context.Context, req *CreatePassw
// Persist to storage.
e, err := b.Save(ctx)
if err != nil {
switch {
case ent.IsNotSingular(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
case ent.IsConstraintError(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
// Reload the entity to attach all eager-loaded edges.
q := h.client.PasswordToken.Query().Where(passwordtoken.ID(e.ID))
@ -71,23 +55,8 @@ func (h *OgentHandler) ReadPasswordToken(ctx context.Context, params ReadPasswor
q := h.client.PasswordToken.Query().Where(passwordtoken.IDEQ(params.ID))
e, err := q.Only(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsNotSingular(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
return NewPasswordTokenRead(e), nil
}
@ -109,23 +78,8 @@ func (h *OgentHandler) UpdatePasswordToken(ctx context.Context, req *UpdatePassw
// Persist to storage.
e, err := b.Save(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsConstraintError(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
// Reload the entity to attach all eager-loaded edges.
q := h.client.PasswordToken.Query().Where(passwordtoken.ID(e.ID))
@ -141,23 +95,8 @@ func (h *OgentHandler) UpdatePasswordToken(ctx context.Context, req *UpdatePassw
func (h *OgentHandler) DeletePasswordToken(ctx context.Context, params DeletePasswordTokenParams) (DeletePasswordTokenRes, error) {
err := h.client.PasswordToken.DeleteOneID(params.ID).Exec(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsConstraintError(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
return new(DeletePasswordTokenNoContent), nil
@ -178,23 +117,8 @@ func (h *OgentHandler) ListPasswordToken(ctx context.Context, params ListPasswor
es, err := q.All(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsNotSingular(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
r := NewPasswordTokenLists(es)
return (*ListPasswordTokenOKApplicationJSON)(&r), nil
@ -205,23 +129,8 @@ func (h *OgentHandler) ReadPasswordTokenUser(ctx context.Context, params ReadPas
q := h.client.PasswordToken.Query().Where(passwordtoken.IDEQ(params.ID)).QueryUser()
e, err := q.Only(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsNotSingular(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
return NewPasswordTokenUserRead(e), nil
}
@ -240,23 +149,8 @@ func (h *OgentHandler) CreateUser(ctx context.Context, req *CreateUserReq) (Crea
// Persist to storage.
e, err := b.Save(ctx)
if err != nil {
switch {
case ent.IsNotSingular(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
case ent.IsConstraintError(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
// Reload the entity to attach all eager-loaded edges.
q := h.client.User.Query().Where(user.ID(e.ID))
@ -273,23 +167,8 @@ func (h *OgentHandler) ReadUser(ctx context.Context, params ReadUserParams) (Rea
q := h.client.User.Query().Where(user.IDEQ(params.ID))
e, err := q.Only(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsNotSingular(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
return NewUserRead(e), nil
}
@ -317,23 +196,8 @@ func (h *OgentHandler) UpdateUser(ctx context.Context, req *UpdateUserReq, param
// Persist to storage.
e, err := b.Save(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsConstraintError(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
// Reload the entity to attach all eager-loaded edges.
q := h.client.User.Query().Where(user.ID(e.ID))
@ -349,23 +213,8 @@ func (h *OgentHandler) UpdateUser(ctx context.Context, req *UpdateUserReq, param
func (h *OgentHandler) DeleteUser(ctx context.Context, params DeleteUserParams) (DeleteUserRes, error) {
err := h.client.User.DeleteOneID(params.ID).Exec(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsConstraintError(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
return new(DeleteUserNoContent), nil
@ -386,23 +235,8 @@ func (h *OgentHandler) ListUser(ctx context.Context, params ListUserParams) (Lis
es, err := q.All(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsNotSingular(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
r := NewUserLists(es)
return (*ListUserOKApplicationJSON)(&r), nil
@ -422,23 +256,8 @@ func (h *OgentHandler) ListUserOwner(ctx context.Context, params ListUserOwnerPa
q.Limit(itemsPerPage).Offset((page - 1) * itemsPerPage)
es, err := q.All(ctx)
if err != nil {
switch {
case ent.IsNotFound(err):
return &R404{
Code: http.StatusNotFound,
Status: http.StatusText(http.StatusNotFound),
Errors: rawError(err),
}, nil
case ent.IsNotSingular(err):
return &R409{
Code: http.StatusConflict,
Status: http.StatusText(http.StatusConflict),
Errors: rawError(err),
}, nil
default:
// Let the server handle the error.
return nil, err
}
// Let the server handle the error.
return nil, err
}
r := NewUserOwnerLists(es)
return (*ListUserOwnerOKApplicationJSON)(&r), nil

View file

@ -124,8 +124,20 @@ func (h *Admin) EntityAddSubmit(p AdminEntityPlugin) echo.HandlerFunc {
if err != nil {
return fail(err, fmt.Sprintf("failed to bind create password token request body"))
}
fmt.Printf("%+v", v)
return h.EntityAdd(p)(ctx)
res, err := h.ogent.CreatePasswordToken(ctx.Request().Context(), &v)
if err != nil {
msg.Danger(ctx, err.Error())
return h.EntityAdd(p)(ctx)
}
fmt.Printf("%+v\n", res)
msg.Success(ctx, fmt.Sprintf("Successfully added %s.", strings.ToLower(p.Label)))
return redirect.
New(ctx).
Route(p.RouteNameList()).
Go()
}
}

View file

@ -1,7 +1,6 @@
package components
import (
"fmt"
"strings"
"github.com/mikestefanello/pagoda/pkg/ui"
@ -16,32 +15,6 @@ func JS(r *ui.Request) Node {
}
}
func HtmxListeners(r *ui.Request) Node {
const htmxErr = `
document.body.addEventListener('htmx:beforeSwap', function(evt) {
if (evt.detail.xhr.status >= 400){
evt.detail.shouldSwap = true;
evt.detail.target = htmx.find("body");
}
});
`
const htmxCSRF = `
document.body.addEventListener('htmx:configRequest', function(evt) {
if (evt.detail.verb !== "get") {
evt.detail.parameters['csrf'] = '%s';
}
})
`
return Group{
Script(Raw(htmxErr)),
Iff(len(r.CSRF) > 0, func() Node {
return Script(Raw(fmt.Sprintf(htmxCSRF, r.CSRF)))
}),
}
}
func CSS() Node {
return Link(
Href("https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css"),

View file

@ -1,9 +1,39 @@
package components
import (
"fmt"
"github.com/mikestefanello/pagoda/pkg/ui"
. "maragu.dev/gomponents"
. "maragu.dev/gomponents/html"
)
func HtmxListeners(r *ui.Request) Node {
const htmxErr = `
document.body.addEventListener('htmx:beforeSwap', function(evt) {
if (evt.detail.xhr.status >= 400){
evt.detail.shouldSwap = true;
evt.detail.target = htmx.find("body");
}
});
`
const htmxCSRF = `
document.body.addEventListener('htmx:configRequest', function(evt) {
if (evt.detail.verb !== "get") {
evt.detail.parameters['csrf'] = '%s';
}
})
`
return Group{
Script(Raw(htmxErr)),
Iff(len(r.CSRF) > 0, func() Node {
return Script(Raw(fmt.Sprintf(htmxCSRF, r.CSRF)))
}),
}
}
func HxBoost() Node {
return Attr("hx-boost", "true")
}

View file

@ -66,6 +66,7 @@ func AdminEntityAdd(ctx echo.Context, schema *load.Schema) error {
InputType: "text",
Label: label(f.Name),
Help: fmt.Sprintf("Use the following format: %s", time.Now().Format(time.RFC3339)),
Value: time.Now().Format(time.RFC3339),
}))
case field.TypeBool:
nodes = append(nodes, P(Textf("%s not supported", f.Name)))