+
+ Submitting this form will create an ExampleTask in the task queue. After the specified delay, the message will be logged by the queue processor.
+See pkg/tasks and the README for more information.
+diff --git a/pkg/form/submission.go b/pkg/form/submission.go index 7e5513a..88d898f 100644 --- a/pkg/form/submission.go +++ b/pkg/form/submission.go @@ -103,6 +103,8 @@ func (f *Submission) setErrorMessages(err error) { message = "Enter a valid email address." case "eqfield": message = "Does not match." + case "gte": + message = fmt.Sprintf("Must be greater than or equal to %v.", ve.Param()) default: message = "Invalid value." } diff --git a/pkg/handlers/cache.go b/pkg/handlers/cache.go new file mode 100644 index 0000000..acdc5b2 --- /dev/null +++ b/pkg/handlers/cache.go @@ -0,0 +1,90 @@ +package handlers + +import ( + "errors" + "github.com/labstack/echo/v4" + "github.com/mikestefanello/pagoda/pkg/form" + "github.com/mikestefanello/pagoda/pkg/page" + "github.com/mikestefanello/pagoda/pkg/services" + "github.com/mikestefanello/pagoda/templates" + "time" +) + +const ( + routeNameCache = "cache" + routeNameCacheSubmit = "cache.submit" +) + +type ( + Cache struct { + cache *services.CacheClient + *services.TemplateRenderer + } + + cacheForm struct { + Value string `form:"value"` + form.Submission + } +) + +func init() { + Register(new(Cache)) +} + +func (h *Cache) Init(c *services.Container) error { + h.TemplateRenderer = c.TemplateRenderer + h.cache = c.Cache + return nil +} + +func (h *Cache) Routes(g *echo.Group) { + g.GET("/cache", h.Page).Name = routeNameCache + g.POST("/cache", h.Submit).Name = routeNameCacheSubmit +} + +func (h *Cache) Page(ctx echo.Context) error { + p := page.New(ctx) + p.Layout = templates.LayoutMain + p.Name = templates.PageCache + p.Title = "Set a cache entry" + p.Form = form.Get[cacheForm](ctx) + + // Fetch the value from the cache + value, err := h.cache.Get(). + Key("page_cache_example"). + Fetch(ctx.Request().Context()) + + // Store the value in the page so it can be rendered, if found + switch { + case err == nil: + p.Data = value.(string) + case errors.Is(err, services.ErrCacheMiss): + default: + return fail(err, "failed to fetch from cache") + } + + return h.RenderPage(ctx, p) +} + +func (h *Cache) Submit(ctx echo.Context) error { + var input cacheForm + + if err := form.Submit(ctx, &input); err != nil { + return err + } + + // Set the cache + err := h.cache.Set(). + Key("page_cache_example"). + Data(input.Value). + Expiration(10 * time.Minute). + Save(ctx.Request().Context()) + + if err != nil { + return fail(err, "unable to set cache") + } + + form.Clear(ctx) + + return h.Page(ctx) +} diff --git a/pkg/handlers/contact.go b/pkg/handlers/contact.go index 0273364..4c5f264 100644 --- a/pkg/handlers/contact.go +++ b/pkg/handlers/contact.go @@ -2,14 +2,11 @@ package handlers import ( "fmt" - "time" - "github.com/go-playground/validator/v10" "github.com/labstack/echo/v4" "github.com/mikestefanello/pagoda/pkg/form" "github.com/mikestefanello/pagoda/pkg/page" "github.com/mikestefanello/pagoda/pkg/services" - "github.com/mikestefanello/pagoda/pkg/tasks" "github.com/mikestefanello/pagoda/templates" ) @@ -20,8 +17,7 @@ const ( type ( Contact struct { - mail *services.MailClient - tasks *services.TaskClient + mail *services.MailClient *services.TemplateRenderer } @@ -40,7 +36,6 @@ func init() { func (h *Contact) Init(c *services.Container) error { h.TemplateRenderer = c.TemplateRenderer h.mail = c.Mail - h.tasks = c.Tasks return nil } @@ -72,16 +67,6 @@ func (h *Contact) Submit(ctx echo.Context) error { return err } - // TODO create a new page for this - err = h.tasks.New(tasks.ExampleTask{ - Message: input.Message, - }). - Wait(10 * time.Second). - Save() - if err != nil { - return err - } - err = h.mail. Compose(). To(input.Email). diff --git a/pkg/handlers/task.go b/pkg/handlers/task.go new file mode 100644 index 0000000..f4abc64 --- /dev/null +++ b/pkg/handlers/task.go @@ -0,0 +1,88 @@ +package handlers + +import ( + "fmt" + "github.com/mikestefanello/pagoda/pkg/msg" + "time" + + "github.com/go-playground/validator/v10" + "github.com/labstack/echo/v4" + "github.com/mikestefanello/pagoda/pkg/form" + "github.com/mikestefanello/pagoda/pkg/page" + "github.com/mikestefanello/pagoda/pkg/services" + "github.com/mikestefanello/pagoda/pkg/tasks" + "github.com/mikestefanello/pagoda/templates" +) + +const ( + routeNameTask = "task" + routeNameTaskSubmit = "task.submit" +) + +type ( + Task struct { + tasks *services.TaskClient + *services.TemplateRenderer + } + + taskForm struct { + Delay int `form:"delay" validate:"gte=0"` + Message string `form:"message" validate:"required"` + form.Submission + } +) + +func init() { + Register(new(Task)) +} + +func (h *Task) Init(c *services.Container) error { + h.TemplateRenderer = c.TemplateRenderer + h.tasks = c.Tasks + return nil +} + +func (h *Task) Routes(g *echo.Group) { + g.GET("/task", h.Page).Name = routeNameTask + g.POST("/task", h.Submit).Name = routeNameTaskSubmit +} + +func (h *Task) Page(ctx echo.Context) error { + p := page.New(ctx) + p.Layout = templates.LayoutMain + p.Name = templates.PageTask + p.Title = "Create a task" + p.Form = form.Get[taskForm](ctx) + + return h.RenderPage(ctx, p) +} + +func (h *Task) Submit(ctx echo.Context) error { + var input taskForm + + err := form.Submit(ctx, &input) + + switch err.(type) { + case nil: + case validator.ValidationErrors: + return h.Page(ctx) + default: + return err + } + + // Insert the task + err = h.tasks.New(tasks.ExampleTask{ + Message: input.Message, + }). + Wait(time.Duration(input.Delay) * time.Second). + Save() + + if err != nil { + return fail(err, "unable to create a task") + } + + msg.Success(ctx, fmt.Sprintf("The task has been created. Check the logs in %d seconds.", input.Delay)) + form.Clear(ctx) + + return h.Page(ctx) +} diff --git a/templates/layouts/main.gohtml b/templates/layouts/main.gohtml index e256c9c..66f872b 100644 --- a/templates/layouts/main.gohtml +++ b/templates/layouts/main.gohtml @@ -28,6 +28,8 @@