diff --git a/ent/entc.go b/ent/entc.go index 66899ae..76a388a 100644 --- a/ent/entc.go +++ b/ent/entc.go @@ -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) } diff --git a/ent/ogent/ogent.go b/ent/ogent/ogent.go index 379e59b..21939e6 100644 --- a/ent/ogent/ogent.go +++ b/ent/ogent/ogent.go @@ -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 diff --git a/pkg/handlers/admin.go b/pkg/handlers/admin.go index 80446da..a1fe7e5 100644 --- a/pkg/handlers/admin.go +++ b/pkg/handlers/admin.go @@ -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() } } diff --git a/pkg/ui/components/head.go b/pkg/ui/components/head.go index 0ce6701..e4016b4 100644 --- a/pkg/ui/components/head.go +++ b/pkg/ui/components/head.go @@ -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"), diff --git a/pkg/ui/components/htmx.go b/pkg/ui/components/htmx.go index d62cb58..e4f97f0 100644 --- a/pkg/ui/components/htmx.go +++ b/pkg/ui/components/htmx.go @@ -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") } diff --git a/pkg/ui/pages/entity.go b/pkg/ui/pages/entity.go index 7362263..71129e2 100644 --- a/pkg/ui/pages/entity.go +++ b/pkg/ui/pages/entity.go @@ -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)))