Skip to content

Commit

Permalink
Use consts for route names and templates.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikestefanello committed Dec 16, 2023
1 parent 5af18e2 commit c2b6928
Show file tree
Hide file tree
Showing 30 changed files with 135 additions and 82 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,11 @@ Cached pages are looked up for a key that matches the exact, full URL of the giv

### Data

The `Data` field on the `Page` is of type `interface{}` and is what allows your route to pass whatever it requires to the templates, alongside the `Page` itself.
The `Data` field on the `Page` is of type `any` and is what allows your route to pass whatever it requires to the templates, alongside the `Page` itself.

### Forms

The `Form` field on the `Page` is similar to the `Data` field in that it's an `interface{}` type but it's meant to store a struct that represents a form being rendered on the page.
The `Form` field on the `Page` is similar to the `Data` field in that it's an `any` type but it's meant to store a struct that represents a form being rendered on the page.

An example of this pattern is:

Expand Down Expand Up @@ -825,8 +825,8 @@ Once your `Page` is fully built, rendering it via the embedded `Controller` in y
```go
func (c *home) Get(ctx echo.Context) error {
page := controller.NewPage(ctx)
page.Layout = "main"
page.Name = "home"
page.Layout = templates.LayoutMain
page.Name = templates.PageHome
return c.RenderPage(ctx, page)
}
```
Expand Down
8 changes: 4 additions & 4 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (c *Controller) RenderPage(ctx echo.Context, page Page) error {
buf, err = c.Container.TemplateRenderer.
Parse().
Group("page:htmx").
Key(page.Name).
Key(string(page.Name)).
Base("htmx").
Files(
"htmx",
Expand All @@ -73,8 +73,8 @@ func (c *Controller) RenderPage(ctx echo.Context, page Page) error {
buf, err = c.Container.TemplateRenderer.
Parse().
Group("page").
Key(page.Name).
Base(page.Layout).
Key(string(page.Name)).
Base(string(page.Layout)).
Files(
fmt.Sprintf("layouts/%s", page.Layout),
fmt.Sprintf("pages/%s", page.Name),
Expand Down Expand Up @@ -151,7 +151,7 @@ func (c *Controller) cachePage(ctx echo.Context, page Page, html *bytes.Buffer)
}

// Redirect redirects to a given route name with optional route parameters
func (c *Controller) Redirect(ctx echo.Context, route string, routeParams ...interface{}) error {
func (c *Controller) Redirect(ctx echo.Context, route string, routeParams ...any) error {
url := ctx.Echo().Reverse(route, routeParams...)

if htmx.GetRequest(ctx).Boosted {
Expand Down
11 changes: 6 additions & 5 deletions pkg/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controller

import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"os"
Expand Down Expand Up @@ -91,14 +92,14 @@ func TestController_RenderPage(t *testing.T) {
}

// Check the template cache
parsed, err := c.TemplateRenderer.Load("page", p.Name)
parsed, err := c.TemplateRenderer.Load("page", string(p.Name))
assert.NoError(t, err)

// Check that all expected templates were parsed.
// This includes the name, layout and all components
expectedTemplates := make(map[string]bool)
expectedTemplates[p.Name+config.TemplateExt] = true
expectedTemplates[p.Layout+config.TemplateExt] = true
expectedTemplates[fmt.Sprintf("%s%s", p.Name, config.TemplateExt)] = true
expectedTemplates[fmt.Sprintf("%s%s", p.Layout, config.TemplateExt)] = true
components, err := templates.Get().ReadDir("components")
require.NoError(t, err)
for _, f := range components {
Expand All @@ -124,13 +125,13 @@ func TestController_RenderPage(t *testing.T) {
assert.Equal(t, "trigger", ctx.Response().Header().Get(htmx.HeaderTrigger))

// Check the template cache
parsed, err := c.TemplateRenderer.Load("page:htmx", p.Name)
parsed, err := c.TemplateRenderer.Load("page:htmx", string(p.Name))
assert.NoError(t, err)

// Check that all expected templates were parsed.
// This includes the name, htmx and all components
expectedTemplates := make(map[string]bool)
expectedTemplates[p.Name+config.TemplateExt] = true
expectedTemplates[fmt.Sprintf("%s%s", p.Name, config.TemplateExt)] = true
expectedTemplates["htmx"+config.TemplateExt] = true
components, err := templates.Get().ReadDir("components")
require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/form.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type FormSubmission struct {
}

// Process processes a submission for a form
func (f *FormSubmission) Process(ctx echo.Context, form interface{}) error {
func (f *FormSubmission) Process(ctx echo.Context, form any) error {
f.Errors = make(map[string][]string)
f.IsSubmitted = true

Expand Down
11 changes: 6 additions & 5 deletions pkg/controller/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/mikestefanello/pagoda/pkg/context"
"github.com/mikestefanello/pagoda/pkg/htmx"
"github.com/mikestefanello/pagoda/pkg/msg"
"github.com/mikestefanello/pagoda/templates"

echomw "github.com/labstack/echo/v4/middleware"

Expand All @@ -34,7 +35,7 @@ type Page struct {
Context echo.Context

// ToURL is a function to convert a route name and optional route parameters to a URL
ToURL func(name string, params ...interface{}) string
ToURL func(name string, params ...any) string

// Path stores the path of the current request
Path string
Expand All @@ -44,24 +45,24 @@ type Page struct {

// Data stores whatever additional data that needs to be passed to the templates.
// This is what the controller uses to pass the content of the page.
Data interface{}
Data any

// Form stores a struct that represents a form on the page.
// This should be a struct with fields for each form field, using both "form" and "validate" tags
// It should also contain a Submission field of type FormSubmission if you wish to have validation
// messagesa and markup presented to the user
Form interface{}
Form any

// Layout stores the name of the layout base template file which will be used when the page is rendered.
// This should match a template file located within the layouts directory inside the templates directory.
// The template extension should not be included in this value.
Layout string
Layout templates.Layout

// Name stores the name of the page as well as the name of the template file which will be used to render
// the content portion of the layout template.
// This should match a template file located within the pages directory inside the templates directory.
// The template extension should not be included in this value.
Name string
Name templates.Page

// IsHome stores whether the requested page is the home page or not
IsHome bool
Expand Down
2 changes: 1 addition & 1 deletion pkg/funcmap/funcmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func GetFuncMap() template.FuncMap {
}

// HasField checks if an interface contains a given field
func HasField(v interface{}, name string) bool {
func HasField(v any, name string) bool {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
Expand Down
2 changes: 1 addition & 1 deletion pkg/funcmap/funcmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestLink(t *testing.T) {
assert.Equal(t, expected, link)
}

func TestGetFuncMap(t *testing.T) {
func TestFile(t *testing.T) {
file := File("test.png")
expected := fmt.Sprintf("/%s/test.png?v=%s", config.StaticPrefix, CacheBuster)
assert.Equal(t, expected, file)
Expand Down
1 change: 1 addition & 0 deletions pkg/middleware/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func LoadValidPasswordToken(authClient *services.AuthClient) echo.MiddlewareFunc
return next(c)
case services.InvalidPasswordTokenError:
msg.Warning(c, "The link is either invalid or has expired. Please request a new one.")
// TODO use the const for route name
return c.Redirect(http.StatusFound, c.Echo().Reverse("forgot_password"))
default:
return echo.NewHTTPError(
Expand Down
5 changes: 3 additions & 2 deletions pkg/routes/about.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"html/template"

"github.com/mikestefanello/pagoda/pkg/controller"
"github.com/mikestefanello/pagoda/templates"

"github.com/labstack/echo/v4"
)
Expand All @@ -27,8 +28,8 @@ type (

func (c *about) Get(ctx echo.Context) error {
page := controller.NewPage(ctx)
page.Layout = "main"
page.Name = "about"
page.Layout = templates.LayoutMain
page.Name = templates.PageAbout
page.Title = "About"

// This page will be cached!
Expand Down
2 changes: 1 addition & 1 deletion pkg/routes/about_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
// this test package
func TestAbout_Get(t *testing.T) {
doc := request(t).
setRoute("about").
setRoute(routeNameAbout).
get().
assertStatusCode(http.StatusOK).
toDoc()
Expand Down
5 changes: 3 additions & 2 deletions pkg/routes/contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/mikestefanello/pagoda/pkg/context"
"github.com/mikestefanello/pagoda/pkg/controller"
"github.com/mikestefanello/pagoda/templates"

"github.com/labstack/echo/v4"
)
Expand All @@ -23,8 +24,8 @@ type (

func (c *contact) Get(ctx echo.Context) error {
page := controller.NewPage(ctx)
page.Layout = "main"
page.Name = "contact"
page.Layout = templates.LayoutMain
page.Name = templates.PageContact
page.Title = "Contact us"
page.Form = contactForm{}

Expand Down
5 changes: 3 additions & 2 deletions pkg/routes/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/mikestefanello/pagoda/pkg/context"
"github.com/mikestefanello/pagoda/pkg/controller"
"github.com/mikestefanello/pagoda/templates"

"github.com/labstack/echo/v4"
)
Expand All @@ -30,9 +31,9 @@ func (e *errorHandler) Get(err error, ctx echo.Context) {
}

page := controller.NewPage(ctx)
page.Layout = "main"
page.Title = http.StatusText(code)
page.Name = "error"
page.Layout = templates.LayoutMain
page.Name = templates.PageError
page.StatusCode = code
page.HTMX.Request.Enabled = false

Expand Down
7 changes: 4 additions & 3 deletions pkg/routes/forgot_password.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/mikestefanello/pagoda/pkg/context"
"github.com/mikestefanello/pagoda/pkg/controller"
"github.com/mikestefanello/pagoda/pkg/msg"
"github.com/mikestefanello/pagoda/templates"

"github.com/labstack/echo/v4"
)
Expand All @@ -26,8 +27,8 @@ type (

func (c *forgotPassword) Get(ctx echo.Context) error {
page := controller.NewPage(ctx)
page.Layout = "auth"
page.Name = "forgot-password"
page.Layout = templates.LayoutAuth
page.Name = templates.PageForgotPassword
page.Title = "Forgot password"
page.Form = forgotPasswordForm{}

Expand Down Expand Up @@ -84,7 +85,7 @@ func (c *forgotPassword) Post(ctx echo.Context) error {
ctx.Logger().Infof("generated password reset token for user %d", u.ID)

// Email the user
url := ctx.Echo().Reverse("reset_password", u.ID, pt.ID, token)
url := ctx.Echo().Reverse(routeNameResetPassword, u.ID, pt.ID, token)
err = c.Container.Mail.
Compose().
To(u.Email).
Expand Down
5 changes: 3 additions & 2 deletions pkg/routes/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/mikestefanello/pagoda/pkg/controller"
"github.com/mikestefanello/pagoda/templates"

"github.com/labstack/echo/v4"
)
Expand All @@ -21,8 +22,8 @@ type (

func (c *home) Get(ctx echo.Context) error {
page := controller.NewPage(ctx)
page.Layout = "main"
page.Name = "home"
page.Layout = templates.LayoutMain
page.Name = templates.PageHome
page.Metatags.Description = "Welcome to the homepage."
page.Metatags.Keywords = []string{"Go", "MVC", "Web", "Software"}
page.Pager = controller.NewPager(ctx, 4)
Expand Down
7 changes: 4 additions & 3 deletions pkg/routes/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/mikestefanello/pagoda/pkg/context"
"github.com/mikestefanello/pagoda/pkg/controller"
"github.com/mikestefanello/pagoda/pkg/msg"
"github.com/mikestefanello/pagoda/templates"

"github.com/labstack/echo/v4"
)
Expand All @@ -27,8 +28,8 @@ type (

func (c *login) Get(ctx echo.Context) error {
page := controller.NewPage(ctx)
page.Layout = "auth"
page.Name = "login"
page.Layout = templates.LayoutAuth
page.Name = templates.PageLogin
page.Title = "Log in"
page.Form = loginForm{}

Expand Down Expand Up @@ -90,5 +91,5 @@ func (c *login) Post(ctx echo.Context) error {
}

msg.Success(ctx, fmt.Sprintf("Welcome back, <strong>%s</strong>. You are now logged in.", u.Name))
return c.Redirect(ctx, "home")
return c.Redirect(ctx, routeNameHome)
}
2 changes: 1 addition & 1 deletion pkg/routes/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ func (l *logout) Get(c echo.Context) error {
} else {
msg.Danger(c, "An error occurred. Please try again.")
}
return l.Redirect(c, "home")
return l.Redirect(c, routeNameHome)
}
13 changes: 7 additions & 6 deletions pkg/routes/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/mikestefanello/pagoda/pkg/context"
"github.com/mikestefanello/pagoda/pkg/controller"
"github.com/mikestefanello/pagoda/pkg/msg"
"github.com/mikestefanello/pagoda/templates"

"github.com/labstack/echo/v4"
)
Expand All @@ -27,8 +28,8 @@ type (

func (c *register) Get(ctx echo.Context) error {
page := controller.NewPage(ctx)
page.Layout = "auth"
page.Name = "register"
page.Layout = templates.LayoutAuth
page.Name = templates.PageRegister
page.Title = "Register"
page.Form = registerForm{}

Expand Down Expand Up @@ -75,7 +76,7 @@ func (c *register) Post(ctx echo.Context) error {
ctx.Logger().Infof("user created: %s", u.Name)
case *ent.ConstraintError:
msg.Warning(ctx, "A user with this email address already exists. Please log in.")
return c.Redirect(ctx, "login")
return c.Redirect(ctx, routeNameLogin)
default:
return c.Fail(err, "unable to create user")
}
Expand All @@ -85,15 +86,15 @@ func (c *register) Post(ctx echo.Context) error {
if err != nil {
ctx.Logger().Errorf("unable to log in: %v", err)
msg.Info(ctx, "Your account has been created.")
return c.Redirect(ctx, "login")
return c.Redirect(ctx, routeNameLogin)
}

msg.Success(ctx, "Your account has been created. You are now logged in.")

// Send the verification email
c.sendVerificationEmail(ctx, u)

return c.Redirect(ctx, "home")
return c.Redirect(ctx, routeNameHome)
}

func (c *register) sendVerificationEmail(ctx echo.Context, usr *ent.User) {
Expand All @@ -105,7 +106,7 @@ func (c *register) sendVerificationEmail(ctx echo.Context, usr *ent.User) {
}

// Send the email
url := ctx.Echo().Reverse("verify_email", token)
url := ctx.Echo().Reverse(routeNameVerifyEmail, token)
err = c.Container.Mail.
Compose().
To(usr.Email).
Expand Down
Loading

0 comments on commit c2b6928

Please sign in to comment.